From 4ea3ff79c350c9af799ed76e72e5c862af3eb73e Mon Sep 17 00:00:00 2001 From: monsta Date: Wed, 14 Dec 2016 15:35:49 +0300 Subject: externaltools plugin: port to gi and libpeas note: tools manager dialog can now be invoked only via Pluma's menu. Preferences button in plugin manager is inactive. re-enabling it would mean introducing even more complexity, because we would need to pass a configure widget to libpeas, not the whole dialog. mostly adapted from: https://git.gnome.org/browse/gedit/commit/?id=8b6d353e0ab94ad52ce6119759db5e14b281fbba https://git.gnome.org/browse/gedit/commit/?id=2aa6071912dac227f04f44c07e07f159b77be7ff https://git.gnome.org/browse/gedit/commit/?id=09738cd6f5f24a37cb7dd85dfca7a5099529e5d2 https://git.gnome.org/browse/gedit/commit/?id=f08e9d2953fa213f77dce635127c3a0131fba02f https://git.gnome.org/browse/gedit/commit/?id=d09a703e84f818dcadd7bd1c16c2091305a691c2 https://git.gnome.org/browse/gedit/commit/?id=985f3908abe3f2ade53db1364dccf0d1fd61ec1b https://git.gnome.org/browse/gedit/commit/?id=b6086cab8c664d2cfb3e5b4a6d33c215d1b207da https://git.gnome.org/browse/gedit/commit/?id=befd854563e4691a6b75b03695d6a7c458836312 https://git.gnome.org/browse/gedit/commit/?id=cf7549c8e5944a3fbf9d18170b6e45a552071b4c https://git.gnome.org/browse/gedit/commit/?id=6c95d28a13ae87232346583a86ae525a22fcc651 https://git.gnome.org/browse/gedit/commit/?id=c70319048b42b898fd6c2f6ee37e98e54cea54be --- plugins/Makefile.am | 4 +- plugins/externaltools/Makefile.am | 6 +- .../externaltools/externaltools.plugin.desktop.in | 9 + .../externaltools.pluma-plugin.desktop.in | 9 - plugins/externaltools/tools/__init__.py | 142 +++++++------- plugins/externaltools/tools/capture.py | 35 ++-- plugins/externaltools/tools/filelookup.py | 13 +- plugins/externaltools/tools/functions.py | 45 ++--- plugins/externaltools/tools/library.py | 5 +- plugins/externaltools/tools/manager.py | 207 ++++++++++++--------- plugins/externaltools/tools/outputpanel.py | 50 ++--- plugins/externaltools/tools/tools.ui | 3 + 12 files changed, 272 insertions(+), 256 deletions(-) create mode 100644 plugins/externaltools/externaltools.plugin.desktop.in delete mode 100644 plugins/externaltools/externaltools.pluma-plugin.desktop.in (limited to 'plugins') diff --git a/plugins/Makefile.am b/plugins/Makefile.am index a27ae69a..495d1a2c 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -1,6 +1,7 @@ DIST_SUBDIRS = \ changecase \ docinfo \ + externaltools \ filebrowser \ modelines \ sort \ @@ -12,6 +13,7 @@ DIST_SUBDIRS = \ SUBDIRS = \ changecase \ docinfo \ + externaltools \ filebrowser \ modelines \ sort \ @@ -20,7 +22,7 @@ SUBDIRS = \ trailsave # python plugins are disabled for now -#SUBDIRS += externaltools pythonconsole snippets quickopen +#SUBDIRS += pythonconsole snippets quickopen if ENABLE_ENCHANT SUBDIRS += spell diff --git a/plugins/externaltools/Makefile.am b/plugins/externaltools/Makefile.am index bec58b63..cd6f9720 100644 --- a/plugins/externaltools/Makefile.am +++ b/plugins/externaltools/Makefile.am @@ -2,10 +2,10 @@ SUBDIRS = tools data scripts plugindir = $(PLUMA_PLUGINS_LIBS_DIR) -plugin_in_files = externaltools.pluma-plugin.desktop.in -%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +plugin_in_files = externaltools.plugin.desktop.in +%.plugin: %.plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) +plugin_DATA = $(plugin_in_files:.plugin.desktop.in=.plugin) EXTRA_DIST = $(plugin_in_files) diff --git a/plugins/externaltools/externaltools.plugin.desktop.in b/plugins/externaltools/externaltools.plugin.desktop.in new file mode 100644 index 00000000..b3261e77 --- /dev/null +++ b/plugins/externaltools/externaltools.plugin.desktop.in @@ -0,0 +1,9 @@ +[Plugin] +Loader=python +Module=externaltools +IAge=2 +_Name=External Tools +_Description=Execute external commands and shell scripts. +Authors=Steve Frécinaux +Copyright=Copyright © 2005 Steve Frécinaux +Website=http://www.mate-desktop.org diff --git a/plugins/externaltools/externaltools.pluma-plugin.desktop.in b/plugins/externaltools/externaltools.pluma-plugin.desktop.in deleted file mode 100644 index 611ca002..00000000 --- a/plugins/externaltools/externaltools.pluma-plugin.desktop.in +++ /dev/null @@ -1,9 +0,0 @@ -[Pluma Plugin] -Loader=python -Module=externaltools -IAge=2 -_Name=External Tools -_Description=Execute external commands and shell scripts. -Authors=Steve Frécinaux -Copyright=Copyright © 2005 Steve Frécinaux -Website=http://www.mate-desktop.org diff --git a/plugins/externaltools/tools/__init__.py b/plugins/externaltools/tools/__init__.py index 39522ede..2a51c97c 100755 --- a/plugins/externaltools/tools/__init__.py +++ b/plugins/externaltools/tools/__init__.py @@ -16,11 +16,9 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -__all__ = ('ExternalToolsPlugin', 'ExternalToolsWindowHelper', - 'Manager', 'OutputPanel', 'Capture', 'UniqueById') +__all__ = ('ExternalToolsPlugin', 'Manager', 'OutputPanel', 'Capture', 'UniqueById') -import pluma -import gtk +from gi.repository import GObject, Gtk, Peas, Pluma from manager import Manager from library import ToolLibrary from outputpanel import OutputPanel @@ -28,17 +26,16 @@ from capture import Capture from functions import * class ToolMenu(object): - ACTION_HANDLER_DATA_KEY = "ExternalToolActionHandlerData" - ACTION_ITEM_DATA_KEY = "ExternalToolActionItemData" - - def __init__(self, library, window, menupath): + def __init__(self, library, window, panel, plugin, menupath): super(ToolMenu, self).__init__() self._library = library self._window = window + self._panel = panel + self._plugin = plugin self._menupath = menupath self._merge_id = 0 - self._action_group = gtk.ActionGroup("ExternalToolsPluginToolActions") + self._action_group = Gtk.ActionGroup("ExternalToolsPluginToolActions") self._signals = [] self.update() @@ -53,17 +50,15 @@ class ToolMenu(object): self._merge_id = 0 for action in self._action_group.list_actions(): - handler = action.get_data(self.ACTION_HANDLER_DATA_KEY) + if action._tool_handler is not None: + action.disconnect(action._tool_handler) - if handler is not None: - action.disconnect(handler) - - action.set_data(self.ACTION_ITEM_DATA_KEY, None) - action.set_data(self.ACTION_HANDLER_DATA_KEY, None) + action._tool_item = None + action._tool_handler = None self._action_group.remove_action(action) - accelmap = gtk.accel_map_get() + accelmap = Gtk.AccelMap.get() for s in self._signals: accelmap.disconnect(s) @@ -75,43 +70,44 @@ class ToolMenu(object): for item in directory.subdirs: action_name = 'ExternalToolDirectory%X' % id(item) - action = gtk.Action(action_name, item.name.replace('_', '__'), None, None) + action = Gtk.Action(action_name, item.name.replace('_', '__'), None, None) self._action_group.add_action(action) manager.add_ui(self._merge_id, path, action_name, action_name, - gtk.UI_MANAGER_MENU, False) + Gtk.UIManagerItemType.MENU, False) self._insert_directory(item, path + '/' + action_name) for item in directory.tools: action_name = 'ExternalToolTool%X' % id(item) - action = gtk.Action(action_name, item.name.replace('_', '__'), item.comment, None) - handler = action.connect("activate", capture_menu_action, self._window, item) + action = Gtk.Action(action_name, item.name.replace('_', '__'), item.comment, None) + handler = action.connect("activate", capture_menu_action, self._window, self._panel, item) - action.set_data(self.ACTION_ITEM_DATA_KEY, item) - action.set_data(self.ACTION_HANDLER_DATA_KEY, handler) + # Attach the item and the handler to the action object + action._tool_item = item + action._tool_handler = handler # Make sure to replace accel accelpath = '/ExternalToolsPluginToolActions/%s' % (action_name, ) if item.shortcut: - key, mod = gtk.accelerator_parse(item.shortcut) - gtk.accel_map_change_entry(accelpath, key, mod, True) + key, mod = Gtk.accelerator_parse(item.shortcut) + Gtk.AccelMap.change_entry(accelpath, key, mod, True) - self._signals.append(gtk.accel_map_get().connect('changed::%s' % (accelpath,), self.on_accelmap_changed, item)) + self._signals.append(Gtk.AccelMap.get().connect('changed::%s' % (accelpath,), self.on_accelmap_changed, item)) self._action_group.add_action_with_accel(action, item.shortcut) manager.add_ui(self._merge_id, path, action_name, action_name, - gtk.UI_MANAGER_MENUITEM, False) + Gtk.UIManagerItemType.MENUITEM, False) def on_accelmap_changed(self, accelmap, path, key, mod, tool): - tool.shortcut = gtk.accelerator_name(key, mod) + tool.shortcut = Gtk.accelerator_name(key, mod) tool.save() - self._window.get_data("ExternalToolsPluginWindowData").update_manager(tool) + self._plugin.update_manager(tool) def update(self): self.remove() @@ -150,29 +146,36 @@ class ToolMenu(object): language = document.get_language() for action in self._action_group.list_actions(): - item = action.get_data(self.ACTION_ITEM_DATA_KEY) + if action._tool_item is not None: + action.set_visible(states[action._tool_item.applicability] and + self.filter_language(language, action._tool_item)) - if item is not None: - action.set_visible(states[item.applicability] and self.filter_language(language, item)) +class ExternalToolsPlugin(GObject.Object, Peas.Activatable): + __gtype_name__ = "ExternalToolsPlugin" -class ExternalToolsWindowHelper(object): - def __init__(self, plugin, window): - super(ExternalToolsWindowHelper, self).__init__() + object = GObject.Property(type=GObject.Object) - self._window = window - self._plugin = plugin + def __init__(self): + GObject.Object.__init__(self) + + self._manager = None + self._manager_default_size = None + + def do_activate(self): self._library = ToolLibrary() + self._library.set_locations(os.path.join(self.plugin_info.get_data_dir(), 'tools')) + window = self.object manager = window.get_ui_manager() - self._action_group = gtk.ActionGroup('ExternalToolsPluginActions') + self._action_group = Gtk.ActionGroup('ExternalToolsPluginActions') self._action_group.set_translation_domain('pluma') self._action_group.add_actions([('ExternalToolManager', None, _('Manage _External Tools...'), None, _("Opens the External Tools Manager"), - lambda action: plugin.open_dialog()), + lambda action: self.open_dialog()), ('ExternalTools', None, _('External _Tools'), @@ -201,69 +204,47 @@ class ExternalToolsWindowHelper(object): self._merge_id = manager.add_ui_from_string(ui_string) - self.menu = ToolMenu(self._library, self._window, + # Create output console + self._output_buffer = OutputPanel(self.plugin_info.get_data_dir(), window) + + self.menu = ToolMenu(self._library, window, self._output_buffer, self, "/MenuBar/ToolsMenu/ToolsOps_4/ExternalToolsMenu/ExternalToolPlaceholder") manager.ensure_update() - # Create output console - self._output_buffer = OutputPanel(self._plugin.get_data_dir(), window) bottom = window.get_bottom_panel() - bottom.add_item(self._output_buffer.panel, - _("Shell Output"), - gtk.STOCK_EXECUTE) + bottom.add_item_with_stock_icon(self._output_buffer.panel, + _("Shell Output"), + Gtk.STOCK_EXECUTE) - def update_ui(self): - self.menu.filter(self._window.get_active_document()) - self._window.get_ui_manager().ensure_update() + def do_deactivate(self): + window = self.object + manager = window.get_ui_manager() - def deactivate(self): - manager = self._window.get_ui_manager() self.menu.deactivate() manager.remove_ui(self._merge_id) manager.remove_action_group(self._action_group) manager.ensure_update() - bottom = self._window.get_bottom_panel() + bottom = window.get_bottom_panel() bottom.remove_item(self._output_buffer.panel) - def update_manager(self, tool): - self._plugin.update_manager(tool) + def do_update_state(self): + window = self.object -class ExternalToolsPlugin(pluma.Plugin): - WINDOW_DATA_KEY = "ExternalToolsPluginWindowData" - - def __init__(self): - super(ExternalToolsPlugin, self).__init__() - - self._manager = None - self._manager_default_size = None - - ToolLibrary().set_locations(os.path.join(self.get_data_dir(), 'tools')) - - def activate(self, window): - helper = ExternalToolsWindowHelper(self, window) - window.set_data(self.WINDOW_DATA_KEY, helper) - - def deactivate(self, window): - window.get_data(self.WINDOW_DATA_KEY).deactivate() - window.set_data(self.WINDOW_DATA_KEY, None) - - def update_ui(self, window): - window.get_data(self.WINDOW_DATA_KEY).update_ui() - - def create_configure_dialog(self): - return self.open_dialog() + self.menu.filter(window.get_active_document()) + window.get_ui_manager().ensure_update() def open_dialog(self): if not self._manager: - self._manager = Manager(self.get_data_dir()) + self._manager = Manager(self.plugin_info.get_data_dir()) if self._manager_default_size: self._manager.dialog.set_default_size(*self._manager_default_size) self._manager.dialog.connect('destroy', self.on_manager_destroy) + self._manager.connect('tools-updated', self.on_manager_tools_updated) - window = pluma.app_get_default().get_active_window() + window = Pluma.App.get_default().get_active_window() self._manager.run(window) return self._manager.dialog @@ -275,7 +256,10 @@ class ExternalToolsPlugin(pluma.Plugin): self._manager.tool_changed(tool, True) def on_manager_destroy(self, dialog): - self._manager_default_size = [dialog.allocation.width, dialog.allocation.height] + self._manager_default_size = self._manager.get_final_size() self._manager = None + def on_manager_tools_updated(self, manager): + self.menu.update() + # ex:ts=4:et: diff --git a/plugins/externaltools/tools/capture.py b/plugins/externaltools/tools/capture.py index 2f065761..487c8dbb 100755 --- a/plugins/externaltools/tools/capture.py +++ b/plugins/externaltools/tools/capture.py @@ -21,11 +21,10 @@ __all__ = ('Capture', ) import os, sys, signal import locale import subprocess -import gobject import fcntl -import glib +from gi.repository import GObject, GLib -class Capture(gobject.GObject): +class Capture(GObject.Object): CAPTURE_STDOUT = 0x01 CAPTURE_STDERR = 0x02 CAPTURE_BOTH = 0x03 @@ -34,14 +33,14 @@ class Capture(gobject.GObject): WRITE_BUFFER_SIZE = 0x4000 __gsignals__ = { - 'stdout-line' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)), - 'stderr-line' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)), - 'begin-execute': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, tuple()), - 'end-execute' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT,)) + 'stdout-line' : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING,)), + 'stderr-line' : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_STRING,)), + 'begin-execute': (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, tuple()), + 'end-execute' : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_INT,)) } def __init__(self, command, cwd = None, env = {}): - gobject.GObject.__init__(self) + GObject.GObject.__init__(self) self.pipe = None self.env = env self.cwd = cwd @@ -101,8 +100,8 @@ class Capture(gobject.GObject): flags = fcntl.fcntl(self.pipe.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK fcntl.fcntl(self.pipe.stdout.fileno(), fcntl.F_SETFL, flags) - gobject.io_add_watch(self.pipe.stdout, - gobject.IO_IN | gobject.IO_HUP, + GLib.io_add_watch(self.pipe.stdout, + GObject.IO_IN | GObject.IO_HUP, self.on_output) if self.flags & self.CAPTURE_STDERR: @@ -110,8 +109,8 @@ class Capture(gobject.GObject): flags = fcntl.fcntl(self.pipe.stderr.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK fcntl.fcntl(self.pipe.stderr.fileno(), fcntl.F_SETFL, flags) - gobject.io_add_watch(self.pipe.stderr, - gobject.IO_IN | gobject.IO_HUP, + GLib.io_add_watch(self.pipe.stderr, + GObject.IO_IN | GObject.IO_HUP, self.on_output) # IO @@ -120,10 +119,10 @@ class Capture(gobject.GObject): self.write_buffer = str(self.input_text) if self.idle_write_chunk(): - self.idle_write_id = gobject.idle_add(self.idle_write_chunk) + self.idle_write_id = GLib.idle_add(self.idle_write_chunk) # Wait for the process to complete - gobject.child_watch_add(self.pipe.pid, self.on_child_end) + GLib.child_watch_add(self.pipe.pid, self.on_child_end) def idle_write_chunk(self): if not self.pipe: @@ -153,7 +152,7 @@ class Capture(gobject.GObject): return False def on_output(self, source, condition): - if condition & (glib.IO_IN | glib.IO_PRI): + if condition & (GLib.IOCondition.IN | GLib.IOCondition.PRI): line = source.read() if len(line) > 0: @@ -179,7 +178,7 @@ class Capture(gobject.GObject): else: self.emit('stderr-line', line) - if condition & ~(glib.IO_IN | glib.IO_PRI): + if condition & ~(GLib.IOCondition.IN | GLib.IOCondition.PRI): if self.read_buffer: if source == self.pipe.stdout: self.emit('stdout-line', self.read_buffer) @@ -197,7 +196,7 @@ class Capture(gobject.GObject): def stop(self, error_code = -1): if self.pipe is not None: if self.idle_write_id: - gobject.source_remove(self.idle_write_id) + GLib.source_remove(self.idle_write_id) self.idle_write_id = 0 if not self.tried_killing: @@ -209,6 +208,6 @@ class Capture(gobject.GObject): def on_child_end(self, pid, error_code): # In an idle, so it is emitted after all the std*-line signals # have been intercepted - gobject.idle_add(self.emit, 'end-execute', error_code) + GLib.idle_add(self.emit, 'end-execute', error_code) # ex:ts=4:et: diff --git a/plugins/externaltools/tools/filelookup.py b/plugins/externaltools/tools/filelookup.py index ce4961f9..aa5abf9b 100755 --- a/plugins/externaltools/tools/filelookup.py +++ b/plugins/externaltools/tools/filelookup.py @@ -17,8 +17,7 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import os -import gio -import pluma +from gi.repository import Gio, Pluma class FileLookup: """ @@ -73,7 +72,7 @@ class AbsoluteFileLookupProvider(FileLookupProvider): def lookup(self, path): if os.path.isabs(path) and os.path.isfile(path): - return gio.File(path) + return Gio.file_new_for_path(path) else: return None @@ -93,7 +92,7 @@ class CwdFileLookupProvider(FileLookupProvider): real_path = os.path.join(cwd, path) if os.path.isfile(real_path): - return gio.File(real_path) + return Gio.file_new_for_path(real_path) else: return None @@ -110,14 +109,14 @@ class OpenDocumentRelPathFileLookupProvider(FileLookupProvider): if path.startswith('/'): return None - for doc in pluma.app_get_default().get_documents(): + for doc in Pluma.App.get_default().get_documents(): if doc.is_local(): location = doc.get_location() if location: rel_path = location.get_parent().get_path() joined_path = os.path.join(rel_path, path) if os.path.isfile(joined_path): - return gio.File(joined_path) + return Gio.file_new_for_path(joined_path) return None @@ -135,7 +134,7 @@ class OpenDocumentFileLookupProvider(FileLookupProvider): if path.startswith('/'): return None - for doc in pluma.app_get_default().get_documents(): + for doc in Pluma.App.get_default().get_documents(): if doc.is_local(): location = doc.get_location() if location and location.get_uri().endswith(path): diff --git a/plugins/externaltools/tools/functions.py b/plugins/externaltools/tools/functions.py index b4b666f6..e1268443 100755 --- a/plugins/externaltools/tools/functions.py +++ b/plugins/externaltools/tools/functions.py @@ -17,11 +17,7 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import os -import gtk -from gtk import gdk -import gio -import pluma -#import gtksourceview +from gi.repository import Gio, Gdk, Gtk, GtkSource, Pluma from outputpanel import OutputPanel from capture import * @@ -44,7 +40,7 @@ def current_word(document): return (start, piter) # ==== Capture related functions ==== -def run_external_tool(window, node): +def run_external_tool(window, panel, node): # Configure capture environment try: cwd = os.getcwd() @@ -87,13 +83,13 @@ def run_external_tool(window, node): capture.set_env(PLUMA_CURRENT_DOCUMENT_TYPE=document.get_mime_type()) if uri is not None: - gfile = gio.File(uri) + gfile = Gio.file_new_for_uri(uri) scheme = gfile.get_uri_scheme() name = os.path.basename(uri) capture.set_env(PLUMA_CURRENT_DOCUMENT_URI = uri, PLUMA_CURRENT_DOCUMENT_NAME = name, PLUMA_CURRENT_DOCUMENT_SCHEME = scheme) - if pluma.utils.uri_has_file_scheme(uri): + if Pluma.utils_uri_has_file_scheme(uri): path = gfile.get_path() cwd = os.path.dirname(path) capture.set_cwd(cwd) @@ -103,9 +99,9 @@ def run_external_tool(window, node): documents_uri = [doc.get_uri() for doc in window.get_documents() if doc.get_uri() is not None] - documents_path = [gio.File(uri).get_path() + documents_path = [Gio.file_new_for_uri(uri).get_path() for uri in documents_uri - if pluma.utils.uri_has_file_scheme(uri)] + if Pluma.utils_uri_has_file_scheme(uri)] capture.set_env(PLUMA_DOCUMENTS_URI = ' '.join(documents_uri), PLUMA_DOCUMENTS_PATH = ' '.join(documents_path)) @@ -120,8 +116,7 @@ def run_external_tool(window, node): input_type = node.input output_type = node.output - # Get the panel - panel = window.get_data("ExternalToolsPluginWindowData")._output_buffer + # Clear the panel panel.clear() if output_type == 'output-panel': @@ -167,7 +162,7 @@ def run_external_tool(window, node): if not end.ends_word(): end.forward_word_end() - input_text = document.get_text(start, end) + input_text = document.get_text(start, end, False) capture.set_input(input_text) # Assign the standard output to the chosen "file" @@ -211,8 +206,9 @@ def run_external_tool(window, node): document.end_user_action() class MultipleDocumentsSaver: - def __init__(self, window, docs, node): + def __init__(self, window, panel, docs, node): self._window = window + self._panel = panel self._node = node self._error = False @@ -224,7 +220,7 @@ class MultipleDocumentsSaver: for doc in docs: signals[doc] = doc.connect('saving', self.on_document_saving) - pluma.commands.save_document(window, doc) + Pluma.commands_save_document(window, doc) doc.disconnect(signals[doc]) def on_document_saving(self, doc, size, total_size): @@ -241,17 +237,17 @@ class MultipleDocumentsSaver: self._counter -= 1 if self._counter == 0 and not self._error: - run_external_tool(self._window, self._node) + run_external_tool(self._window, self._panel, self._node) -def capture_menu_action(action, window, node): +def capture_menu_action(action, window, panel, node): if node.save_files == 'document' and window.get_active_document(): - MultipleDocumentsSaver(window, [window.get_active_document()], node) + MultipleDocumentsSaver(window, panel, [window.get_active_document()], node) return elif node.save_files == 'all': - MultipleDocumentsSaver(window, window.get_documents(), node) + MultipleDocumentsSaver(window, panel, window.get_documents(), node) return - run_external_tool(window, node) + run_external_tool(window, panel, node) def capture_stderr_line_panel(capture, line, panel): if not panel.visible(): @@ -260,7 +256,7 @@ def capture_stderr_line_panel(capture, line, panel): panel.write(line, panel.error_tag) def capture_begin_execute_panel(capture, panel, view, label): - view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(gdk.Cursor(gdk.WATCH)) + view.get_window(Gtk.TextWindowType.TEXT).set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) panel['stop'].set_sensitive(True) panel.clear() @@ -276,15 +272,14 @@ def capture_end_execute_panel(capture, exit_code, panel, view, output_type): end = start.copy() end.forward_chars(300) - mtype = gio.content_type_guess(data=doc.get_text(start, end)) - lmanager = pluma.get_language_manager() - + mtype, uncertain = Gio.content_type_guess(None, doc.get_text(start, end, False).encode('utf-8')) + lmanager = GtkSource.LanguageManager.get_default() language = lmanager.guess_language(doc.get_uri(), mtype) if language is not None: doc.set_language(language) - view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(gdk.Cursor(gdk.XTERM)) + view.get_window(Gtk.TextWindowType.TEXT).set_cursor(Gdk.Cursor.new(Gdk.CursorType.XTERM)) view.set_cursor_visible(True) view.set_editable(True) diff --git a/plugins/externaltools/tools/library.py b/plugins/externaltools/tools/library.py index 09a0cd42..b4e6924e 100755 --- a/plugins/externaltools/tools/library.py +++ b/plugins/externaltools/tools/library.py @@ -19,6 +19,7 @@ import os import re import locale +from gi.repository import GLib class Singleton(object): _instance = None @@ -44,7 +45,7 @@ class ToolLibrary(Singleton): self.locations.append(datadir) # self.locations[0] is where we save the custom scripts - toolsdir = os.path.expanduser('~/.config/pluma/tools') + toolsdir = os.path.join(GLib.get_user_config_dir(), 'pluma/tools') self.locations.insert(0, toolsdir); if not os.path.isdir(self.locations[0]): @@ -68,7 +69,7 @@ class ToolLibrary(Singleton): # storage file. def import_old_xml_store(self): import xml.etree.ElementTree as et - filename = os.path.expanduser('~/.config/pluma/pluma-tools.xml') + filename = os.path.join(GLib.get_user_config_dir(), 'pluma/pluma-tools.xml') if not os.path.isfile(filename): return diff --git a/plugins/externaltools/tools/manager.py b/plugins/externaltools/tools/manager.py index 4d4d50aa..c0656cb8 100755 --- a/plugins/externaltools/tools/manager.py +++ b/plugins/externaltools/tools/manager.py @@ -18,23 +18,22 @@ __all__ = ('Manager', ) -import pluma -import gtk -import gtksourceview2 as gsv import os.path from library import * from functions import * import hashlib from xml.sax import saxutils -import gobject +from gi.repository import GObject, Gio, Gdk, Gtk, GtkSource, Pluma + +class LanguagesPopup(Gtk.Window): + __gtype_name__ = "LanguagePopup" -class LanguagesPopup(gtk.Window): COLUMN_NAME = 0 COLUMN_ID = 1 COLUMN_ENABLED = 2 def __init__(self, languages): - gtk.Window.__init__(self, gtk.WINDOW_POPUP) + Gtk.Window.__init__(self, type=Gtk.WindowType.POPUP) self.set_default_size(200, 200) self.props.can_focus = True @@ -43,44 +42,61 @@ class LanguagesPopup(gtk.Window): self.init_languages(languages) self.show() - self.map() self.grab_add() - gtk.gdk.keyboard_grab(self.window, False, 0L) - gtk.gdk.pointer_grab(self.window, False, gtk.gdk.BUTTON_PRESS_MASK | - gtk.gdk.BUTTON_RELEASE_MASK | - gtk.gdk.POINTER_MOTION_MASK | - gtk.gdk.ENTER_NOTIFY_MASK | - gtk.gdk.LEAVE_NOTIFY_MASK | - gtk.gdk.PROXIMITY_IN_MASK | - gtk.gdk.PROXIMITY_OUT_MASK, None, None, 0L) + self.keyboard = None + device_manager = Gdk.Display.get_device_manager(self.get_window().get_display()) + for device in device_manager.list_devices(Gdk.DeviceType.MASTER): + if device.get_source() == Gdk.InputSource.KEYBOARD: + self.keyboard = device + break + + self.pointer = device_manager.get_client_pointer() + + if self.keyboard is not None: + self.keyboard.grab(self.get_window(), + Gdk.GrabOwnership.WINDOW, False, + Gdk.EventMask.KEY_PRESS_MASK | + Gdk.EventMask.KEY_RELEASE_MASK, + None, Gdk.CURRENT_TIME) + self.pointer.grab(self.get_window(), + Gdk.GrabOwnership.WINDOW, False, + Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK | + Gdk.EventMask.POINTER_MOTION_MASK | + Gdk.EventMask.ENTER_NOTIFY_MASK | + Gdk.EventMask.LEAVE_NOTIFY_MASK | + Gdk.EventMask.PROXIMITY_IN_MASK | + Gdk.EventMask.PROXIMITY_OUT_MASK | + Gdk.EventMask.SCROLL_MASK, + None, Gdk.CURRENT_TIME) self.view.get_selection().select_path((0,)) def build(self): - self.model = gtk.ListStore(str, str, bool) + self.model = Gtk.ListStore(str, str, bool) - self.sw = gtk.ScrolledWindow() + self.sw = Gtk.ScrolledWindow() self.sw.show() - self.sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - self.sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) + self.sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) + self.sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) - self.view = gtk.TreeView(self.model) + self.view = Gtk.TreeView(self.model) self.view.show() self.view.set_headers_visible(False) - column = gtk.TreeViewColumn() + column = Gtk.TreeViewColumn() - renderer = gtk.CellRendererToggle() + renderer = Gtk.CellRendererToggle() column.pack_start(renderer, False) column.set_attributes(renderer, active=self.COLUMN_ENABLED) renderer.connect('toggled', self.on_language_toggled) - renderer = gtk.CellRendererText() + renderer = Gtk.CellRendererText() column.pack_start(renderer, True) column.set_attributes(renderer, text=self.COLUMN_NAME) @@ -94,7 +110,7 @@ class LanguagesPopup(gtk.Window): def enabled_languages(self, model, path, piter, ret): enabled = model.get_value(piter, self.COLUMN_ENABLED) - if path == (0,) and enabled: + if path.get_indices()[0] == 0 and enabled: return True if enabled: @@ -113,8 +129,9 @@ class LanguagesPopup(gtk.Window): return val == '-' def init_languages(self, languages): - manager = gsv.LanguageManager() - langs = pluma.language_manager_list_languages_sorted(manager, True) + manager = GtkSource.LanguageManager() + langs = [manager.get_language(x) for x in manager.get_language_ids()] + langs.sort(key=lambda x: x.get_name()) self.model.append([_('All languages'), None, not languages]) self.model.append(['-', None, False]) @@ -142,7 +159,7 @@ class LanguagesPopup(gtk.Window): self.model.set_value(self.model.get_iter_first(), self.COLUMN_ENABLED, False) def do_key_press_event(self, event): - if event.keyval == gtk.keysyms.Escape: + if event.keyval == Gdk.KEY_Escape: self.destroy() return True else: @@ -155,34 +172,35 @@ class LanguagesPopup(gtk.Window): def in_window(self, event, window=None): if not window: - window = self.window + window = self.get_window() geometry = window.get_geometry() origin = window.get_origin() - return event.x_root >= origin[0] and \ - event.x_root <= origin[0] + geometry[2] and \ - event.y_root >= origin[1] and \ - event.y_root <= origin[1] + geometry[3] + return event.x_root >= origin[1] and \ + event.x_root <= origin[1] + geometry[2] and \ + event.y_root >= origin[2] and \ + event.y_root <= origin[2] + geometry[3] def do_destroy(self): - gtk.gdk.keyboard_ungrab(0L) - gtk.gdk.pointer_ungrab(0L) + if self.keyboard: + self.keyboard.ungrab(Gdk.CURRENT_TIME) + self.pointer.ungrab(Gdk.CURRENT_TIME) - return gtk.Window.do_destroy(self) + return Gtk.Window.do_destroy(self) def setup_event(self, event, window): fr = event.window.get_origin() to = window.get_origin() event.window = window - event.x += fr[0] - to[0] - event.y += fr[1] - to[1] + event.x += fr[1] - to[1] + event.y += fr[2] - to[2] def resolve_widgets(self, root): res = [root] - if isinstance(root, gtk.Container): + if isinstance(root, Gtk.Container): root.forall(lambda x, y: res.extend(self.resolve_widgets(x)), None) return res @@ -196,14 +214,14 @@ class LanguagesPopup(gtk.Window): return res - def propagate_mouse_event(self, event): + def propagate_mouse_event(self, event, reverse=True): allwidgets = self.resolve_widgets(self.get_child()) - allwidgets.reverse() - - orig = [event.x, event.y] + + if reverse: + allwidgets.reverse() for widget in allwidgets: - windows = self.resolve_windows(widget.window) + windows = self.resolve_windows(widget.get_window()) windows.reverse() for window in windows: @@ -231,7 +249,7 @@ class LanguagesPopup(gtk.Window): return self.propagate_mouse_event(event) def do_scroll_event(self, event): - return self.propagate_mouse_event(event) + return self.propagate_mouse_event(event, False) def do_motion_notify_event(self, event): return self.propagate_mouse_event(event) @@ -248,25 +266,33 @@ class LanguagesPopup(gtk.Window): def do_proximity_out_event(self, event): return self.propagate_mouse_event(event) -gobject.type_register(LanguagesPopup) - -class Manager: +class Manager(GObject.Object): TOOL_COLUMN = 0 # For Tree NAME_COLUMN = 1 # For Combo + __gsignals__ = { + 'tools-updated': (GObject.SignalFlags.RUN_LAST, None, ()) + } + def __init__(self, datadir): + GObject.Object.__init__(self) self.datadir = datadir self.dialog = None + self._size = (0, 0) self._languages = {} self._tool_rows = {} self.build() + + def get_final_size(self): + return self._size def build(self): callbacks = { 'on_new_tool_button_clicked' : self.on_new_tool_button_clicked, 'on_remove_tool_button_clicked' : self.on_remove_tool_button_clicked, 'on_tool_manager_dialog_response' : self.on_tool_manager_dialog_response, + 'on_tool_manager_dialog_configure_event': self.on_tool_manager_dialog_configure_event, 'on_tool_manager_dialog_focus_out': self.on_tool_manager_dialog_focus_out, 'on_accelerator_key_press' : self.on_accelerator_key_press, 'on_accelerator_focus_in' : self.on_accelerator_focus_in, @@ -275,7 +301,7 @@ class Manager: } # Load the "main-window" widget from the ui file. - self.ui = gtk.Builder() + self.ui = Gtk.Builder() self.ui.add_from_file(os.path.join(self.datadir, 'ui', 'tools.ui')) self.ui.connect_signals(callbacks) self.dialog = self.ui.get_object('tool-manager-dialog') @@ -345,7 +371,7 @@ class Manager: del self.accelerators[shortcut] def add_tool_to_language(self, tool, language): - if isinstance(language, gsv.Language): + if isinstance(language, GtkSource.Language): lid = language.get_id() else: lid = language @@ -353,7 +379,7 @@ class Manager: if not lid in self._languages: piter = self.model.append(None, [language]) - parent = gtk.TreeRowReference(self.model, self.model.get_path(piter)) + parent = Gtk.TreeRowReference.new(self.model, self.model.get_path(piter)) self._languages[lid] = parent else: parent = self._languages[lid] @@ -364,11 +390,11 @@ class Manager: if not tool in self._tool_rows: self._tool_rows[tool] = [] - self._tool_rows[tool].append(gtk.TreeRowReference(self.model, self.model.get_path(child))) + self._tool_rows[tool].append(Gtk.TreeRowReference.new(self.model, self.model.get_path(child))) return child def add_tool(self, tool): - manager = gsv.LanguageManager() + manager = GtkSource.LanguageManager() ret = None for lang in tool.languages: @@ -391,16 +417,16 @@ class Manager: self.script_hash = None self.accelerators = dict() - self.model = gtk.TreeStore(object) + self.model = Gtk.TreeStore(object) self.view.set_model(self.model) for tool in self.tools.tree.tools: self.add_tool(tool) self.model.set_default_sort_func(self.sort_tools) - self.model.set_sort_column_id(-1, gtk.SORT_ASCENDING) + self.model.set_sort_column_id(-1, Gtk.SortType.ASCENDING) - def sort_tools(self, model, iter1, iter2): + def sort_tools(self, model, iter1, iter2, user_data=None): # For languages, sort All before everything else, otherwise alphabetical t1 = model.get_value(iter1, self.TOOL_COLUMN) t2 = model.get_value(iter2, self.TOOL_COLUMN) @@ -413,7 +439,7 @@ class Manager: return 1 def lang_name(lang): - if isinstance(lang, gsv.Language): + if isinstance(lang, GtkSource.Language): return lang.get_name() else: return _('Plain Text') @@ -428,13 +454,13 @@ class Manager: def __init_tools_view(self): # Tools column - column = gtk.TreeViewColumn('Tools') - renderer = gtk.CellRendererText() + column = Gtk.TreeViewColumn('Tools') + renderer = Gtk.CellRendererText() column.pack_start(renderer, False) renderer.set_property('editable', True) self.view.append_column(column) - column.set_cell_data_func(renderer, self.get_cell_data_cb) + column.set_cell_data_func(renderer, self.get_cell_data_cb, None) renderer.connect('edited', self.on_view_label_cell_edited) renderer.connect('editing-started', self.on_view_label_cell_editing_started) @@ -493,7 +519,8 @@ class Manager: self.current_node.save_files = combo_value(self, 'save-files') buf = self['commands'].get_buffer() - script = buf.get_text(*buf.get_bounds()) + (start, end) = buf.get_bounds() + script = buf.get_text(start, end, False) h = self.compute_hash(script) if h != self.script_hash: # script has changed -> save it @@ -521,7 +548,7 @@ class Manager: if not self.current_node or not self.current_node.languages: self['languages_label'].set_text(_('All Languages')) else: - manager = gsv.LanguageManager() + manager = GtkSource.LanguageManager() langs = [] for lang in self.current_node.languages: @@ -547,8 +574,8 @@ class Manager: buf.end_not_undoable_action() self.script_hash = self.compute_hash(script) - contenttype = gio.content_type_guess(data=script) - lmanager = pluma.get_language_manager() + contenttype, uncertain = Gio.content_type_guess(None, script) + lmanager = GtkSource.LanguageManager.get_default() language = lmanager.guess_language(content_type=contenttype) if language is not None: @@ -605,7 +632,7 @@ class Manager: piter = self.model.iter_parent(piter) tool = self.model.get_value(piter, self.TOOL_COLUMN) - if isinstance(tool, gsv.Language): + if isinstance(tool, GtkSource.Language): return tool.get_id() elif tool: return 'plain' @@ -712,7 +739,7 @@ class Manager: piter = self.model.get_iter(path) tool = self.model.get_value(piter, self.TOOL_COLUMN) - if isinstance(editable, gtk.Entry): + if isinstance(editable, Gtk.Entry): editable.set_text(tool.name) editable.grab_focus() @@ -742,7 +769,7 @@ class Manager: # Check whether accelerator already exists self.remove_accelerator(self.current_node) - name = gtk.accelerator_name(keyval, mod) + name = Gtk.accelerator_name(keyval, mod) if name == '': self.current_node.shorcut = None @@ -752,10 +779,10 @@ class Manager: col = self.accelerator_collision(name, self.current_node) if col: - dialog = gtk.MessageDialog(self.dialog, - gtk.DIALOG_MODAL, - gtk.MESSAGE_ERROR, - gtk.BUTTONS_OK, + dialog = Gtk.MessageDialog(self.dialog, + Gtk.DialogFlags.MODAL, + Gtk.MessageType.ERROR, + Gtk.ButtonsType.CLOSE, _('This accelerator is already bound to %s') % (', '.join(map(lambda x: x.name, col)),)) dialog.run() @@ -771,20 +798,20 @@ class Manager: return True def on_accelerator_key_press(self, entry, event): - mask = event.state & gtk.accelerator_get_default_mod_mask() + mask = event.state & Gtk.accelerator_get_default_mod_mask() - if event.keyval == gtk.keysyms.Escape: + if event.keyval == Gdk.KEY_Escape: entry.set_text(default(self.current_node.shortcut, '')) self['commands'].grab_focus() return True - elif event.keyval == gtk.keysyms.Delete \ - or event.keyval == gtk.keysyms.BackSpace: + elif event.keyval == Gdk.KEY_Delete \ + or event.keyval == Gdk.KEY_BackSpace: entry.set_text('') self.remove_accelerator(self.current_node) self.current_node.shortcut = None self['commands'].grab_focus() return True - elif event.keyval in range(gtk.keysyms.F1, gtk.keysyms.F12 + 1): + elif event.keyval in range(Gdk.KEY_F1, Gdk.KEY_F12 + 1): # New accelerator if self.set_accelerator(event.keyval, mask): entry.set_text(default(self.current_node.shortcut, '')) @@ -792,7 +819,7 @@ class Manager: # Capture all `normal characters` return True - elif gtk.gdk.keyval_to_unicode(event.keyval): + elif Gdk.keyval_to_unicode(event.keyval): if mask: # New accelerator if self.set_accelerator(event.keyval, mask): @@ -817,8 +844,8 @@ class Manager: self.tool_changed(self.current_node) def on_tool_manager_dialog_response(self, dialog, response): - if response == gtk.RESPONSE_HELP: - pluma.help_display(self.dialog, 'pluma', 'pluma-external-tools-plugin') + if response == Gtk.ResponseType.HELP: + Pluma.help_display(self.dialog, 'pluma', 'pluma-external-tools-plugin') return self.on_tool_manager_dialog_focus_out(dialog, None) @@ -827,20 +854,22 @@ class Manager: self.dialog = None self.tools = None + def on_tool_manager_dialog_configure_event(self, dialog, event): + if dialog.get_realized(): + alloc = dialog.get_allocation() + self._size = (alloc.width, alloc.height) + def on_tool_manager_dialog_focus_out(self, dialog, event): self.save_current_tool() + self.emit('tools-updated') - for window in pluma.app_get_default().get_windows(): - helper = window.get_data("ExternalToolsPluginWindowData") - helper.menu.update() - - def get_cell_data_cb(self, column, cell, model, piter): + def get_cell_data_cb(self, column, cell, model, piter, user_data=None): tool = model.get_value(piter, self.TOOL_COLUMN) if tool == None or not isinstance(tool, Tool): if tool == None: label = _('All Languages') - elif not isinstance(tool, gsv.Language): + elif not isinstance(tool, GtkSource.Language): label = _('Plain Text') else: label = tool.get_name() @@ -869,7 +898,7 @@ class Manager: for row in self._tool_rows[tool]: path = row.get_path() - if path[0] == parent[0]: + if path.get_indices()[0] == parent.get_indices()[0]: return True return False @@ -882,7 +911,7 @@ class Manager: ret = None if node: - ref = gtk.TreeRowReference(self.model, self.model.get_path(piter)) + ref = Gtk.TreeRowReference(self.model, self.model.get_path(piter)) # Update languages, make sure to inhibit selection change stuff self.view.get_selection().handler_block(self.selection_changed_id) @@ -908,7 +937,7 @@ class Manager: del self._languages[language] # Now, add for any that are new - manager = gsv.LanguageManager() + manager = GtkSource.LanguageManager() for lang in self.current_node.languages: if not self.tool_in_language(self.current_node, lang): @@ -940,8 +969,8 @@ class Manager: popup = LanguagesPopup(self.current_node.languages) popup.set_transient_for(self.dialog) - origin = button.window.get_origin() - popup.move(origin[0], origin[1] - popup.allocation.height) + origin = button.get_window().get_origin() + popup.move(origin[1], origin[2] - popup.get_allocation().height) popup.connect('destroy', self.update_languages) diff --git a/plugins/externaltools/tools/outputpanel.py b/plugins/externaltools/tools/outputpanel.py index 9d1da65f..9613d78c 100755 --- a/plugins/externaltools/tools/outputpanel.py +++ b/plugins/externaltools/tools/outputpanel.py @@ -19,17 +19,13 @@ __all__ = ('OutputPanel', 'UniqueById') -import gtk, pluma -import pango -import gobject import os from weakref import WeakKeyDictionary from capture import * -from gtk import gdk import re -import gio import linkparsing import filelookup +from gi.repository import GLib, Gdk, Gtk, Pango, Pluma class UniqueById: __shared_state = WeakKeyDictionary() @@ -58,12 +54,12 @@ class OutputPanel(UniqueById): } self.window = window - self.ui = gtk.Builder() + self.ui = Gtk.Builder() self.ui.add_from_file(os.path.join(datadir, 'ui', 'outputpanel.ui')) self.ui.connect_signals(callbacks) self.panel = self["output-panel"] - self['view'].modify_font(pango.FontDescription('Monospace')) + self['view'].override_font(Pango.font_description_from_string('Monospace')) buffer = self['view'].get_buffer() @@ -73,18 +69,18 @@ class OutputPanel(UniqueById): self.error_tag.set_property('foreground', 'red') self.italic_tag = buffer.create_tag('italic') - self.italic_tag.set_property('style', pango.STYLE_OBLIQUE) + self.italic_tag.set_property('style', Pango.Style.OBLIQUE) self.bold_tag = buffer.create_tag('bold') - self.bold_tag.set_property('weight', pango.WEIGHT_BOLD) + self.bold_tag.set_property('weight', Pango.Weight.BOLD) self.invalid_link_tag = buffer.create_tag('invalid_link') self.link_tag = buffer.create_tag('link') - self.link_tag.set_property('underline', pango.UNDERLINE_SINGLE) + self.link_tag.set_property('underline', Pango.Underline.SINGLE) - self.link_cursor = gdk.Cursor(gdk.HAND2) - self.normal_cursor = gdk.Cursor(gdk.XTERM) + self.link_cursor = Gdk.Cursor.new(Gdk.CursorType.HAND2) + self.normal_cursor = Gdk.Cursor.new(Gdk.CursorType.XTERM) self.process = None @@ -108,7 +104,7 @@ class OutputPanel(UniqueById): def scroll_to_end(self): iter = self['view'].get_buffer().get_end_iter() - self['view'].scroll_to_iter(iter, 0.0) + self['view'].scroll_to_iter(iter, 0.0, False, 0.5, 0.5) return False # don't requeue this handler def clear(self): @@ -153,7 +149,7 @@ class OutputPanel(UniqueById): buffer.apply_tag(tag, start_iter, end_iter) buffer.delete_mark(insert) - gobject.idle_add(self.scroll_to_end) + GLib.idle_add(self.scroll_to_end) def show(self): panel = self.window.get_bottom_panel() @@ -166,16 +162,16 @@ class OutputPanel(UniqueById): else: cursor = self.normal_cursor - view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(cursor) + view.get_window(Gtk.TextWindowType.TEXT).set_cursor(cursor) def on_view_motion_notify_event(self, view, event): - if event.window == view.get_window(gtk.TEXT_WINDOW_TEXT): + if event.window == view.get_window(Gtk.TextWindowType.TEXT): self.update_cursor_style(view, int(event.x), int(event.y)) return False def on_view_visibility_notify_event(self, view, event): - if event.window == view.get_window(gtk.TEXT_WINDOW_TEXT): + if event.window == view.get_window(Gtk.TextWindowType.TEXT): x, y, m = event.window.get_pointer() self.update_cursor_style(view, x, y) @@ -192,9 +188,17 @@ class OutputPanel(UniqueById): """ # get the offset within the buffer from the x,y coordinates - buff_x, buff_y = view.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, + buff_x, buff_y = view.window_to_buffer_coords(Gtk.TextWindowType.TEXT, x, y) - iter_at_xy = view.get_iter_at_location(buff_x, buff_y) + # usual API breakage in GTK+3, nothing new... + # see https://bugzilla.gnome.org/768793 + if Gtk.get_minor_version() >= 20: + (over_text, iter_at_xy) = view.get_iter_at_location(buff_x, buff_y) + if not over_text: + return None + else: + iter_at_xy = view.get_iter_at_location(buff_x, buff_y) + offset = iter_at_xy.get_offset() # find the first link that contains the offset @@ -206,8 +210,8 @@ class OutputPanel(UniqueById): return None def on_view_button_press_event(self, view, event): - if event.button != 1 or event.type != gdk.BUTTON_PRESS or \ - event.window != view.get_window(gtk.TEXT_WINDOW_TEXT): + if event.button != 1 or event.type != Gdk.EventType.BUTTON_PRESS or \ + event.window != view.get_window(Gtk.TextWindowType.TEXT): return False link = self.get_link_at_location(view, int(event.x), int(event.y)) @@ -217,8 +221,8 @@ class OutputPanel(UniqueById): gfile = self.file_lookup.lookup(link.path) if gfile: - pluma.commands.load_uri(self.window, gfile.get_uri(), None, + Pluma.commands.load_uri(self.window, gfile.get_uri(), None, link.line_nr) - gobject.idle_add(self.idle_grab_focus) + GLib.idle_add(self.idle_grab_focus) # ex:ts=4:et: diff --git a/plugins/externaltools/tools/tools.ui b/plugins/externaltools/tools/tools.ui index fde220d1..afdd3f9d 100644 --- a/plugins/externaltools/tools/tools.ui +++ b/plugins/externaltools/tools/tools.ui @@ -131,6 +131,7 @@ 500 dialog True + @@ -551,6 +552,8 @@ + True + True 1 -- cgit v1.2.1