[meld] Support new tab opening using D-Bus (closes bgo#616466, bgo#453670)



commit e08baf625ba002e1c6f6ea46d9222bc3e1ec289a
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Sat Dec 10 06:34:42 2011 +1000

    Support new tab opening using D-Bus (closes bgo#616466, bgo#453670)
    
    The goal of this patch is to support opening new tabs in an existing
    instance from the command line, enabled by passing a new command line
    flag. Communication between instances is enabled by D-Bus.
    
    New tab opening is not the default behaviour, since many VC systems
    launch Meld and block waiting for an exit code to indicate success or
    failure when doing merges, and we can't break this expectation.
    
    This commit introduces an optional dependency on dbus packages.
    
    Based on a patch from Kacper Wysocki and Antoine.

 bin/meld             |   12 ++++++++-
 meld/dbus_service.py |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++
 meld/meldapp.py      |   17 ++++++++++++-
 3 files changed, 86 insertions(+), 4 deletions(-)
---
diff --git a/bin/meld b/bin/meld
index e5e8250..3c3b431 100755
--- a/bin/meld
+++ b/bin/meld
@@ -133,9 +133,17 @@ gtk.icon_theme_get_default().append_search_path(meld.paths.icon_dir())
 
 def main():
     from meld.meldapp import app
+    try:
+        import meld.dbus_service
+        already_running, dbus_app = meld.dbus_service.setup(app)
+    except ImportError:
+        already_running, dbus_app = False, None
+    meld.meldapp.dbus_app = dbus_app
+
     app.create_window()
-    app.parse_args(sys.argv[1:])
-    gtk.main()
+    new_window = app.parse_args(sys.argv[1:])
+    if new_window or not already_running:
+        gtk.main()
 
 if profiling:
     import profile
diff --git a/meld/dbus_service.py b/meld/dbus_service.py
new file mode 100644
index 0000000..6b446ea
--- /dev/null
+++ b/meld/dbus_service.py
@@ -0,0 +1,61 @@
+# Copyright (C) 2011 Kai Willadsen <kai willadsen gmail com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""This module encapsulates optional D-Bus support for Meld."""
+
+import dbus
+import dbus.bus
+import dbus.service
+import dbus.mainloop.glib
+
+
+DBUS_NAME = "org.gnome.Meld"
+DBUS_PATH = "/org/gnome/Meld"
+
+if getattr(dbus, 'version', (0, 0, 0)) < (0, 83, 0):
+    raise ImportError("Unsupported dbus version")
+
+
+class DBusProvider(dbus.service.Object):
+    """Implements a simple interface for controlling a MeldApp."""
+
+    def __init__(self, bus, name, path, app):
+        dbus.service.Object.__init__(self, bus, path, name)
+        self.app = app
+
+    @dbus.service.method(DBUS_NAME, in_signature='asu')
+    def OpenPaths(self, args, timestamp):
+        """Attempt to open a new tab comparing the passed paths.
+
+        If a valid timestamp is not available, pass 0.
+        """
+        self.app.window.open_paths(args)
+        if timestamp > 0:
+            self.app.window.widget.present_with_time(timestamp)
+        else:
+            self.app.window.widget.present()
+
+
+def setup(app):
+    """Request and return a dbus interface for controlling the MeldApp."""
+    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+    bus = dbus.SessionBus()
+    request = bus.request_name(DBUS_NAME, dbus.bus.NAME_FLAG_DO_NOT_QUEUE)
+    already_running = request == dbus.bus.REQUEST_NAME_REPLY_EXISTS
+    if already_running:
+        obj = dbus.Interface(bus.get_object(DBUS_NAME, DBUS_PATH), DBUS_NAME)
+    else:
+        obj = DBusProvider(bus, DBUS_NAME, DBUS_PATH, app)
+    return already_running, obj
diff --git a/meld/meldapp.py b/meld/meldapp.py
index 20544b5..c4adf3c 100644
--- a/meld/meldapp.py
+++ b/meld/meldapp.py
@@ -167,6 +167,8 @@ class MeldApp(gobject.GObject):
             version="%prog " + version)
         parser.add_option("-L", "--label", action="append", default=[],
             help=_("Set label to use instead of file name"))
+        parser.add_option("-n", "--newtab", action="store_true", default=False,
+            help=_("Open a new tab in an already running instance"))
         parser.add_option("-a", "--auto-compare", action="store_true", default=False,
             help=_("Automatically compare all differing files on startup"))
         parser.add_option("-u", "--unified", action="store_true",
@@ -183,18 +185,29 @@ class MeldApp(gobject.GObject):
         elif len(args) == 4 and any([os.path.isdir(f) for f in args]):
             parser.error(_("can't compare more than three directories"))
 
+        new_window = True
+        open_paths = self.window.open_paths
+        if options.newtab:
+            if not dbus_app:
+                print _("D-Bus error; comparisons will open in a new window.")
+            else:
+                open_paths = lambda f, x: dbus_app.OpenPaths(f, 0)
+                new_window = False
+
         for files in options.diff:
             if len(files) == 4 and any([os.path.isdir(f) for f in files]):
                 parser.error(_("can't compare more than three directories"))
-            self.window.open_paths(files)
+            open_paths(files)
 
-        tab = self.window.open_paths(args, options.auto_compare)
+        tab = open_paths(args, options.auto_compare)
         if options.label and tab:
             tab.set_labels(options.label)
 
         if options.outfile and tab and isinstance(tab, filediff.FileDiff):
             tab.set_merge_output_file(options.outfile)
 
+        return new_window
+
 
 app = MeldApp()
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]