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/externaltools/tools/manager.py | 207 +++++++++++++++++++-------------- 1 file changed, 118 insertions(+), 89 deletions(-) (limited to 'plugins/externaltools/tools/manager.py') 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) -- cgit v1.2.1