[pitivi] Use GObject.Object instead of Signallable



commit 0de1e04eff4c2a6077467bc14b537fd616844278
Author: Alexandru Băluț <alexandru balut gmail com>
Date:   Tue Apr 22 09:31:56 2014 +0200

    Use GObject.Object instead of Signallable

 pitivi/application.py                 |    5 +-
 pitivi/dialogs/filelisterrordialog.py |   17 +-
 pitivi/dialogs/prefs.py               |    2 +-
 pitivi/dialogs/startupwizard.py       |    6 +-
 pitivi/medialibrary.py                |   24 +--
 pitivi/project.py                     |   37 ++--
 pitivi/render.py                      |   20 ++-
 pitivi/settings.py                    |   32 +++-
 pitivi/timeline/previewers.py         |   68 +++++---
 pitivi/titleeditor.py                 |    2 -
 pitivi/transitions.py                 |   11 +-
 pitivi/undo/effect.py                 |    3 +
 pitivi/undo/medialibrary.py           |    2 +
 pitivi/undo/timeline.py               |   43 ++++--
 pitivi/undo/undo.py                   |   76 +++++----
 pitivi/utils/pipeline.py              |  100 +++++------
 pitivi/utils/signal.py                |  258 ---------------------------
 pitivi/utils/system.py                |   14 +-
 pitivi/utils/threads.py               |   17 +-
 pitivi/utils/timeline.py              |   34 ++--
 tests/Makefile.am                     |    1 -
 tests/test_application.py             |   21 +--
 tests/test_project.py                 |   70 ++++----
 tests/test_signallable.py             |  311 ---------------------------------
 tests/test_undo.py                    |    4 +
 25 files changed, 330 insertions(+), 848 deletions(-)
---
diff --git a/pitivi/application.py b/pitivi/application.py
index cd49a16..a2d9863 100644
--- a/pitivi/application.py
+++ b/pitivi/application.py
@@ -57,7 +57,7 @@ class Pitivi(Gtk.Application, Loggable):
     """
 
     __gsignals__ = {
-        'version-info-received': (GObject.SIGNAL_RUN_LAST, None, (object,))
+        "version-info-received": (GObject.SIGNAL_RUN_LAST, None, (object,))
     }
 
     def __init__(self):
@@ -72,7 +72,7 @@ class Pitivi(Gtk.Application, Loggable):
         self.system = None
         self.project_manager = ProjectManager(self)
 
-        self.action_log = None
+        self.action_log = UndoableActionLog()
         self.timeline_log_observer = None
         self.project_log_observer = None
 
@@ -99,7 +99,6 @@ class Pitivi(Gtk.Application, Loggable):
         self.effects = EffectsHandler()
         self.system = getSystem()
 
-        self.action_log = UndoableActionLog()
         self.action_log.connect("commit", self._actionLogCommit)
         self.action_log.connect("undo", self._actionLogUndo)
         self.action_log.connect("redo", self._actionLogRedo)
diff --git a/pitivi/dialogs/filelisterrordialog.py b/pitivi/dialogs/filelisterrordialog.py
index 26f2585..fb08d94 100644
--- a/pitivi/dialogs/filelisterrordialog.py
+++ b/pitivi/dialogs/filelisterrordialog.py
@@ -23,25 +23,28 @@
 Dialog box listing files which had errors, and the reasons.
 """
 
-from gi.repository import Gtk
 import os
+from urllib.parse import unquote
+
+from gi.repository import GObject
+from gi.repository import Gtk
 from gi.repository import Pango
 
 from gettext import gettext as _
 
-from urllib.parse import unquote
 from pitivi.configure import get_ui_dir
-from pitivi.utils.signal import Signallable
 from pitivi.utils.loggable import Loggable
 
 
-class FileListErrorDialog(Signallable, Loggable):
+class FileListErrorDialog(GObject.Object, Loggable):
     """ Dialog box for showing errors in a list of files """
-    __signals__ = {
-        'close': None,
-        'response': ["something"]}
+
+    __gsignals__ = {
+        'close': (GObject.SIGNAL_RUN_LAST, None, ()),
+        'response': (GObject.SIGNAL_RUN_LAST, None, (object,))}
 
     def __init__(self, title, headline):
+        GObject.Object.__init__(self)
         Loggable.__init__(self)
         self.builder = Gtk.Builder()
         self.builder.add_from_file(os.path.join(get_ui_dir(),
diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py
index 3435a22..acc515b 100644
--- a/pitivi/dialogs/prefs.py
+++ b/pitivi/dialogs/prefs.py
@@ -369,7 +369,7 @@ class PreferencesDialog(object):
         value = getattr(self.settings, attrname)
         if attrname not in self.original_values:
             self.original_values[attrname] = value
-            if attrname + "Changed" not in GlobalSettings.get_signals():
+            if not GlobalSettings.notifiesConfigOption(attrname):
                 self.restart_warning.show()
             self.revert_button.set_sensitive(True)
 
diff --git a/pitivi/dialogs/startupwizard.py b/pitivi/dialogs/startupwizard.py
index 8ed3828..ba1d7c6 100644
--- a/pitivi/dialogs/startupwizard.py
+++ b/pitivi/dialogs/startupwizard.py
@@ -147,9 +147,9 @@ class StartUpWizard(object):
         @type project_manager: L{ProjectManager}
         """
         if fully_loaded:
-            project_manager.disconnect_by_function(self._projectFailedCb)
-            project_manager.disconnect_by_function(self._projectLoadedCb)
-            project_manager.disconnect_by_function(self._projectLoadingCb)
+            project_manager.disconnect_by_func(self._projectFailedCb)
+            project_manager.disconnect_by_func(self._projectLoadedCb)
+            project_manager.disconnect_by_func(self._projectLoadingCb)
 
     def _projectLoadingCb(self, unused_project_manager, unused_project):
         """Handle the start of a project load operation."""
diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py
index 4472674..622aada 100644
--- a/pitivi/medialibrary.py
+++ b/pitivi/medialibrary.py
@@ -50,7 +50,6 @@ from pitivi.dialogs.filelisterrordialog import FileListErrorDialog
 from pitivi.dialogs.clipmediaprops import ClipMediaPropsDialog
 from pitivi.utils.ui import beautify_length
 from pitivi.utils.misc import PathWalker, quote_uri, path_from_uri
-from pitivi.utils.signal import SignalGroup
 from pitivi.utils.loggable import Loggable
 import pitivi.utils.ui as dnd
 from pitivi.utils.ui import beautify_info, info_name, SPACING
@@ -251,7 +250,6 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
 
         # Connect to project.  We must remove and reset the callbacks when
         # changing project.
-        self.project_signals = SignalGroup()
         project_manager = self.app.project_manager
         project_manager.connect("new-project-created", self._newProjectCreatedCb)
         project_manager.connect("new-project-loaded", self._newProjectLoadedCb)
@@ -396,21 +394,14 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
         return icon
 
     def _connectToProject(self, project):
-        """Connect signal handlers to a project.
-
-        This first disconnects any handlers connected to an old project.
-        If project is None, this just disconnects any connected handlers.
         """
-        self.project_signals.connect(project, "asset-added", None,
-                self._assetAddedCb)
-        self.project_signals.connect(project, "asset-removed", None,
-                self._assetRemovedCb)
-        self.project_signals.connect(project, "error-loading-asset",
-                 None, self._errorCreatingAssetCb)
-        self.project_signals.connect(project, "done-importing", None,
-                self._sourcesStoppedImportingCb)
-        self.project_signals.connect(project, "start-importing", None,
-                self._sourcesStartedImportingCb)
+        Connect signal handlers to a project.
+        """
+        project.connect("asset-added", self._assetAddedCb)
+        project.connect("asset-removed", self._assetRemovedCb)
+        project.connect("error-loading-asset", self._errorCreatingAssetCb)
+        project.connect("done-importing", self._sourcesStoppedImportingCb)
+        project.connect("start-importing", self._sourcesStartedImportingCb)
 
         # The start-importing signal would have already been emited at that
         # time, make sure to catch if it is the case
@@ -1008,7 +999,6 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
 
     def _newProjectFailedCb(self, unused_pitivi, unused_reason, unused_uri):
         self.storemodel.clear()
-        self.project_signals.disconnectAll()
         self._project = None
 
     def _addUris(self, uris):
diff --git a/pitivi/project.py b/pitivi/project.py
index c554927..e3a8f5b 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -43,7 +43,6 @@ from pitivi.configure import get_ui_dir
 from pitivi.utils.misc import quote_uri, path_from_uri, isWritable
 from pitivi.utils.pipeline import PipelineError, Seeker
 from pitivi.utils.loggable import Loggable
-from pitivi.utils.signal import Signallable
 from pitivi.utils.pipeline import Pipeline
 from pitivi.utils.widgets import FractionWidget
 from pitivi.utils.ripple_update_group import RippleUpdateGroup
@@ -64,6 +63,7 @@ DEFAULT_AUDIO_ENCODER = "vorbisenc"
 
 class AssetRemovedAction(UndoableAction):
     def __init__(self, project, asset):
+        UndoableAction.__init__(self)
         self.project = project
         self.asset = asset
 
@@ -76,6 +76,7 @@ class AssetRemovedAction(UndoableAction):
 
 class AssetAddedAction(UndoableAction):
     def __init__(self, project, asset):
+        UndoableAction.__init__(self)
         self.project = project
         self.asset = asset
 
@@ -89,6 +90,7 @@ class AssetAddedAction(UndoableAction):
 class ProjectSettingsChanged(UndoableAction):
 
     def __init__(self, project, old, new):
+        UndoableAction.__init__(self)
         self.project = project
         self.oldsettings = old
         self.newsettings = new
@@ -105,6 +107,7 @@ class ProjectSettingsChanged(UndoableAction):
 class ProjectLogObserver(UndoableAction):
 
     def __init__(self, log):
+        UndoableAction.__init__(self)
         self.log = log
 
     def startObserving(self, project):
@@ -141,30 +144,28 @@ class ProjectLogObserver(UndoableAction):
         self.log.push(action)
 
 
-class ProjectManager(Signallable, Loggable):
+class ProjectManager(GObject.Object, Loggable):
     """
     @type app: L{Pitivi}
     @type current_project: L{Project}
     @param disable_save: Whether saving is disabled to enforce using save-as.
     """
 
-    __signals__ = {
-        "new-project-loading": ["uri"],
-        "new-project-created": ["project"],
-        "new-project-failed": ["uri", "exception"],
-        "new-project-loaded": ["project", "fully_ready"],
-        "save-project-failed": ["uri", "exception"],
-        "project-saved": ["project", "uri"],
-        "closing-project": ["project"],
-        "project-closed": ["project"],
-        "missing-uri": ["formatter", "uri", "factory"],
-        "reverting-to-saved": ["project"],
+    __gsignals__ = {
+        "new-project-loading": (GObject.SIGNAL_RUN_LAST, None, (str,)),
+        "new-project-created": (GObject.SIGNAL_RUN_LAST, None, (object,)),
+        "new-project-failed": (GObject.SIGNAL_RUN_LAST, None, (str, object)),
+        "new-project-loaded": (GObject.SIGNAL_RUN_LAST, None, (object, bool)),
+        "save-project-failed": (GObject.SIGNAL_RUN_LAST, None, (str, object)),
+        "project-saved": (GObject.SIGNAL_RUN_LAST, None, (object, str)),
+        "closing-project": (GObject.SIGNAL_RUN_LAST, bool, (object,)),
+        "project-closed": (GObject.SIGNAL_RUN_LAST, None, (object,)),
+        "missing-uri": (GObject.SIGNAL_RUN_LAST, str, (object, str, object)),
+        "reverting-to-saved": (GObject.SIGNAL_RUN_LAST, bool, (object,)),
     }
 
-    _instance = None
-
     def __init__(self, app):
-        Signallable.__init__(self)
+        GObject.Object.__init__(self)
         Loggable.__init__(self)
         self.app = app
         self.current_project = None
@@ -533,7 +534,7 @@ class ProjectManager(Signallable, Loggable):
         name, ext = os.path.splitext(uri)
         return name + ext + "~"
 
-    def _missingURICb(self, project, error, asset, unused_what=None):
+    def _missingURICb(self, project, error, asset):
         return self.emit("missing-uri", project, error, asset)
 
     def _projectLoadedCb(self, unused_project, unused_timeline):
@@ -848,7 +849,7 @@ class Project(Loggable, GES.Project):
     @render_scale.setter
     def render_scale(self, value):
         if value:
-            return self.set_meta("render-scale", value)
+            self.set_meta("render-scale", value)
 
     # ------------------------------------------ #
     # GES.Project virtual methods implementation #
diff --git a/pitivi/render.py b/pitivi/render.py
index bbd02a7..ecf642f 100644
--- a/pitivi/render.py
+++ b/pitivi/render.py
@@ -28,10 +28,11 @@ import os
 import subprocess
 import time
 
+from gi.repository import GES
 from gi.repository import GLib
-from gi.repository import Gtk
+from gi.repository import GObject
 from gi.repository import Gst
-from gi.repository import GES
+from gi.repository import Gtk
 
 from gettext import gettext as _
 
@@ -41,7 +42,6 @@ from pitivi.check import PYCANBERRA_SOFT_DEPENDENCY
 from pitivi.utils.loggable import Loggable
 from pitivi.utils.misc import show_user_manual, path_from_uri
 from pitivi.utils.ripple_update_group import RippleUpdateGroup
-from pitivi.utils.signal import Signallable
 from pitivi.utils.ui import model, frame_rates, audio_rates,\
     audio_channels, get_combo_value, set_combo_value, beautify_ETA
 from pitivi.utils.widgets import GstElementSettingsDialog
@@ -220,14 +220,18 @@ def factorylist(factories):
     return model(columns, data)
 
 
-#--------------------------------- Public classes -----------------------------#
-class RenderingProgressDialog(Signallable):
-    __signals__ = {
-        "pause": [],
-        "cancel": [],
+# --------------------------------- Public classes -----------------------------#
+
+class RenderingProgressDialog(GObject.Object):
+
+    __gsignals__ = {
+        "pause": (GObject.SIGNAL_RUN_LAST, None, ()),
+        "cancel": (GObject.SIGNAL_RUN_LAST, None, ()),
     }
 
     def __init__(self, app, parent):
+        GObject.Object.__init__(self)
+
         self.app = app
         self.main_render_dialog = parent
         self.builder = Gtk.Builder()
diff --git a/pitivi/settings.py b/pitivi/settings.py
index b324f8a..90739a3 100644
--- a/pitivi/settings.py
+++ b/pitivi/settings.py
@@ -23,8 +23,7 @@ import os
 from configparser import SafeConfigParser, ParsingError
 
 from gi.repository import GLib
-
-from pitivi.utils.signal import Signallable
+from gi.repository import GObject
 
 
 def get_bool_env(var):
@@ -102,7 +101,11 @@ class Notification(object):
 
     def __init__(self, attrname):
         self.attrname = "_" + attrname
-        self.signame = attrname + "Changed"
+        self.signame = self.signalName(attrname)
+
+    @staticmethod
+    def signalName(attrname):
+        return attrname + "Changed"
 
     def __get__(self, instance, unused):
         return getattr(instance, self.attrname)
@@ -112,7 +115,7 @@ class Notification(object):
         instance.emit(self.signame)
 
 
-class GlobalSettings(Signallable):
+class GlobalSettings(GObject.Object):
     """
     Pitivi app settings.
 
@@ -130,10 +133,11 @@ class GlobalSettings(Signallable):
     options = {}
     environment = set()
     defaults = {}
-    __signals__ = {}
+
+    __gsignals__ = {}
 
     def __init__(self, **unused_kwargs):
-        Signallable.__init__(self)
+        GObject.Object.__init__(self)
         self._config = SafeConfigParser()
         self._readSettingsFromConfigurationFile()
         self._readSettingsFromEnvironmentVariables()
@@ -278,7 +282,7 @@ class GlobalSettings(Signallable):
         signals when modified (default is False).
         @type notify: C{boolean}
         """
-        if section and not section in cls.options:
+        if section and section not in cls.options:
             raise ConfigError("You must add the section \"%s\" first." % section)
         if key and not section:
             raise ConfigError("You must specify a section for key \"%s\"" % key)
@@ -295,9 +299,14 @@ class GlobalSettings(Signallable):
         if not type_:
             type_ = type(default)
         if notify:
-            setattr(cls, attrname, Notification(attrname))
+            notification = Notification(attrname)
+            setattr(cls, attrname, notification)
             setattr(cls, "_" + attrname, default)
-            cls.__signals__[attrname + 'Changed'] = []
+            GObject.signal_new(notification.signame,
+                               cls,
+                               GObject.SIGNAL_RUN_LAST,
+                               None,
+                               ())
         else:
             setattr(cls, attrname, default)
         if section and key:
@@ -316,3 +325,8 @@ class GlobalSettings(Signallable):
         if section in cls.options:
             raise ConfigError("Duplicate Section \"%s\"." % section)
         cls.options[section] = {}
+
+    @classmethod
+    def notifiesConfigOption(cls, attrname):
+        signal_name = Notification.signalName(attrname)
+        GObject.signal_lookup(signal_name, cls)
diff --git a/pitivi/timeline/previewers.py b/pitivi/timeline/previewers.py
index b65bd83..302faf6 100644
--- a/pitivi/timeline/previewers.py
+++ b/pitivi/timeline/previewers.py
@@ -21,7 +21,6 @@
 # Boston, MA 02110-1301, USA.
 
 from datetime import datetime, timedelta
-from gi.repository import Clutter, Gst, GLib, GdkPixbuf, Cogl, GES
 from random import randrange
 import cairo
 import numpy
@@ -29,6 +28,14 @@ import os
 import pickle
 import sqlite3
 
+from gi.repository import Clutter
+from gi.repository import Cogl
+from gi.repository import GES
+from gi.repository import GObject
+from gi.repository import GLib
+from gi.repository import GdkPixbuf
+from gi.repository import Gst
+
 # Our C module optimizing waveforms rendering
 try:
     from . import renderer
@@ -37,7 +44,6 @@ except ImportError:
     import renderer
 
 from pitivi.settings import get_dir, xdg_cache_home
-from pitivi.utils.signal import Signallable
 from pitivi.utils.loggable import Loggable
 from pitivi.utils.misc import binary_search, filename_from_uri, quantize, quote_uri, hash_file, format_ns
 from pitivi.utils.system import CPUUsageTracker
@@ -55,6 +61,12 @@ THUMB_MARGIN_PX = 3
 WAVEFORM_UPDATE_INTERVAL = timedelta(microseconds=500000)
 MARGIN = 500  # For the waveforms, ensures we always have a little extra surface when scrolling while 
playing.
 
+PREVIEW_GENERATOR_SIGNALS = {
+    "done": (GObject.SIGNAL_RUN_LAST, None, ()),
+    "error": (GObject.SIGNAL_RUN_LAST, None, ()),
+}
+
+
 """
 Convention throughout this file:
 Every GES element which name could be mistaken with a UI element
@@ -67,10 +79,9 @@ class PreviewGeneratorManager():
     Manage the execution of PreviewGenerators
     """
     def __init__(self):
-        self._cpipeline = {
-            GES.TrackType.AUDIO: None,
-            GES.TrackType.VIDEO: None
-        }
+        # The current PreviewGenerator per GES.TrackType.
+        self._cpipeline = {}
+        # The queue of PreviewGenerators.
         self._pipelines = {
             GES.TrackType.AUDIO: [],
             GES.TrackType.VIDEO: []
@@ -79,32 +90,33 @@ class PreviewGeneratorManager():
     def addPipeline(self, pipeline):
         track_type = pipeline.track_type
 
+        current_pipeline = self._cpipeline.get(track_type)
         if pipeline in self._pipelines[track_type] or \
-                pipeline is self._cpipeline[track_type]:
+                pipeline is current_pipeline:
+            # Already in the queue or already processing.
             return
 
-        if not self._pipelines[track_type] and self._cpipeline[track_type] is None:
+        if not self._pipelines[track_type] and current_pipeline is None:
             self._setPipeline(pipeline)
         else:
             self._pipelines[track_type].insert(0, pipeline)
 
     def _setPipeline(self, pipeline):
         self._cpipeline[pipeline.track_type] = pipeline
-        PreviewGenerator.connect(pipeline, "done", self._nextPipeline)
+        pipeline.connect("done", self._nextPipeline)
         pipeline.startGeneration()
 
     def _nextPipeline(self, controlled):
         track_type = controlled.track_type
-        if self._cpipeline[track_type]:
-            PreviewGenerator.disconnect_by_function(self._cpipeline[track_type],
-                                                    self._nextPipeline)
-            self._cpipeline[track_type] = None
+        pipeline = self._cpipeline.pop(track_type, None)
+        if pipeline:
+            pipeline.disconnect_by_func(self._nextPipeline)
 
         if self._pipelines[track_type]:
             self._setPipeline(self._pipelines[track_type].pop())
 
 
-class PreviewGenerator(Signallable):
+class PreviewGenerator(object):
     """
     Interface to be implemented by classes that generate previews
     It is need to implement it so PreviewGeneratorManager can manage
@@ -115,16 +127,10 @@ class PreviewGenerator(Signallable):
     # all the generators.
     __manager = PreviewGeneratorManager()
 
-    __signals__ = {
-        "done": [],
-        "error": [],
-    }
-
     def __init__(self, track_type):
         """
         @param track_type : GES.TrackType.*
         """
-        Signallable.__init__(self)
         self.track_type = track_type
 
     def startGeneration(self):
@@ -141,16 +147,21 @@ class PreviewGenerator(Signallable):
 
 
 class VideoPreviewer(Clutter.ScrollActor, PreviewGenerator, Zoomable, Loggable):
+
+    # We could define them in PreviewGenerator, but then for some reason they
+    # are ignored.
+    __gsignals__ = PREVIEW_GENERATOR_SIGNALS
+
     def __init__(self, bElement, timeline):
         """
         @param bElement : the backend GES.TrackElement
         @param track : the track to which the bElement belongs
         @param timeline : the containing graphic timeline.
         """
-        Zoomable.__init__(self)
         Clutter.ScrollActor.__init__(self)
-        Loggable.__init__(self)
         PreviewGenerator.__init__(self, GES.TrackType.VIDEO)
+        Zoomable.__init__(self)
+        Loggable.__init__(self)
 
         # Variables related to the timeline objects
         self.timeline = timeline
@@ -523,7 +534,7 @@ class VideoPreviewer(Clutter.ScrollActor, PreviewGenerator, Zoomable, Loggable):
             self.pipeline.set_state(Gst.State.NULL)
             self.pipeline.get_state(Gst.CLOCK_TIME_NONE)
             self.pipeline = None
-        PreviewGenerator.emit(self, "done")
+        self.emit("done")
 
     def cleanup(self):
         self.stopGeneration()
@@ -537,7 +548,6 @@ class Thumbnail(Clutter.Actor):
         self.props.content = image
         self.width = width
         self.height = height
-        #self.set_background_color(Clutter.Color.new(0, 100, 150, 100))
         self.set_opacity(0)
         self.set_size(self.width, self.height)
         self.has_pixel_data = False
@@ -619,7 +629,7 @@ class ThumbnailCache(Loggable):
             self.warning("JPEG compression failed")
             return
         blob = sqlite3.Binary(jpeg)
-        #Replace if the key already existed
+        # Replace if a row with the same time already exists.
         self._cur.execute("DELETE FROM Thumbs WHERE  time=?", (key,))
         self._cur.execute("INSERT INTO Thumbs VALUES (?,?)", (key, blob,))
 
@@ -725,11 +735,15 @@ class AudioPreviewer(Clutter.Actor, PreviewGenerator, Zoomable, Loggable):
     """
     Audio previewer based on the results from the "level" gstreamer element.
     """
+
+    __gsignals__ = PREVIEW_GENERATOR_SIGNALS
+
     def __init__(self, bElement, timeline):
         Clutter.Actor.__init__(self)
+        PreviewGenerator.__init__(self, GES.TrackType.AUDIO)
         Zoomable.__init__(self)
         Loggable.__init__(self)
-        PreviewGenerator.__init__(self, GES.TrackType.AUDIO)
+
         self.pipeline = None
         self.discovered = False
         self.bElement = bElement
@@ -967,7 +981,7 @@ class AudioPreviewer(Clutter.Actor, PreviewGenerator, Zoomable, Loggable):
             self.pipeline.set_state(Gst.State.NULL)
             self.pipeline.get_state(Gst.CLOCK_TIME_NONE)
 
-        PreviewGenerator.emit(self, "done")
+        self.emit("done")
 
     def cleanup(self):
         self.stopGeneration()
diff --git a/pitivi/titleeditor.py b/pitivi/titleeditor.py
index a95ecf3..34097b1 100644
--- a/pitivi/titleeditor.py
+++ b/pitivi/titleeditor.py
@@ -33,7 +33,6 @@ from gettext import gettext as _
 from pitivi.configure import get_ui_dir
 from pitivi.utils.loggable import Loggable
 from pitivi.utils.pipeline import Seeker
-from pitivi.utils.signal import Signallable
 from pitivi.utils.timeline import SELECT
 from pitivi.utils.ui import argb_to_gdk_rgba, gdk_rgba_to_argb
 
@@ -51,7 +50,6 @@ class TitleEditor(Loggable):
 
     def __init__(self, app):
         Loggable.__init__(self)
-        Signallable.__init__(self)
         self.app = app
         self.settings = {}
         self.source = None
diff --git a/pitivi/transitions.py b/pitivi/transitions.py
index 7e8afea..f58fbb9 100644
--- a/pitivi/transitions.py
+++ b/pitivi/transitions.py
@@ -22,8 +22,9 @@
 
 import os
 
-from gi.repository import GLib
 from gi.repository import GES
+from gi.repository import GLib
+from gi.repository import GObject
 from gi.repository import Gtk
 from gi.repository import GdkPixbuf
 
@@ -31,8 +32,8 @@ from gettext import gettext as _
 
 from pitivi.configure import get_pixmap_dir
 from pitivi.utils.loggable import Loggable
-from pitivi.utils.signal import Signallable
-from pitivi.utils.ui import SPACING, PADDING
+from pitivi.utils.ui import SPACING
+
 
 (COL_TRANSITION_ASSET,
  COL_NAME_TEXT,
@@ -40,7 +41,7 @@ from pitivi.utils.ui import SPACING, PADDING
  COL_ICON) = list(range(4))
 
 
-class TransitionsListWidget(Signallable, Gtk.VBox, Loggable):
+class TransitionsListWidget(Gtk.VBox, Loggable):
     """
     Widget for configuring the selected transition.
 
@@ -50,7 +51,6 @@ class TransitionsListWidget(Signallable, Gtk.VBox, Loggable):
     def __init__(self, app):
         Gtk.VBox.__init__(self)
         Loggable.__init__(self)
-        Signallable.__init__(self)
 
         self.app = app
         self.element = None
@@ -358,4 +358,3 @@ class TransitionsListWidget(Signallable, Gtk.VBox, Loggable):
         text = self.searchEntry.get_text().lower()
         return text in model.get_value(iter, COL_DESC_TEXT).lower() or\
             text in model.get_value(iter, COL_NAME_TEXT).lower()
-        return False
diff --git a/pitivi/undo/effect.py b/pitivi/undo/effect.py
index f854009..efe5663 100644
--- a/pitivi/undo/effect.py
+++ b/pitivi/undo/effect.py
@@ -29,6 +29,7 @@ from pitivi.effects import PROPS_TO_IGNORE
 
 class EffectPropertyChanged(UndoableAction):
     def __init__(self, effect, property_name, old_value, new_value):
+        UndoableAction.__init__(self)
         self.effect = effect
         self.property_name = property_name
         self.old_value = old_value
@@ -89,6 +90,7 @@ class EffectAdded(UndoableAction):
     # to the Effect when undoing so we reset theirs effect when
     # doing it again. The way of doing it is the same with EffectRemoved
     def __init__(self, clip, effect, properties_watcher):
+        UndoableAction.__init__(self)
         self.clip = clip
         self.effect = effect
         self.asset = effect.get_asset()
@@ -121,6 +123,7 @@ class EffectAdded(UndoableAction):
 
 class EffectRemoved(UndoableAction):
     def __init__(self, clip, effect, properties_watcher):
+        UndoableAction.__init__(self)
         self.effect = effect
         self.clip = clip
         self.asset = effect.get_asset()
diff --git a/pitivi/undo/medialibrary.py b/pitivi/undo/medialibrary.py
index 8bd6623..1b27941 100644
--- a/pitivi/undo/medialibrary.py
+++ b/pitivi/undo/medialibrary.py
@@ -24,6 +24,7 @@ from pitivi.undo.undo import UndoableAction
 
 class MediaLibrarySourceAddedAction(UndoableAction):
     def __init__(self, medialibrary, source):
+        UndoableAction.__init__(self)
         self.medialibrary = medialibrary
         self.source = source
 
@@ -38,6 +39,7 @@ class MediaLibrarySourceAddedAction(UndoableAction):
 
 class MediaLibrarySourceRemovedAction(UndoableAction):
     def __init__(self, medialibrary, uri, source):
+        UndoableAction.__init__(self)
         self.medialibrary = medialibrary
         self.uri = uri
         self.source = source
diff --git a/pitivi/undo/timeline.py b/pitivi/undo/timeline.py
index ca9e231..9bb4ffc 100644
--- a/pitivi/undo/timeline.py
+++ b/pitivi/undo/timeline.py
@@ -20,7 +20,8 @@
 # Boston, MA 02110-1301, USA.
 
 from gi.repository import GES
-from pitivi.utils.signal import Signallable
+from gi.repository import GObject
+
 from pitivi.undo.undo import PropertyChangeTracker, UndoableAction
 from pitivi.undo.effect import EffectAdded, EffectRemoved
 from pitivi.undo.effect import EffectGstElementPropertyChangeTracker
@@ -30,6 +31,9 @@ class ClipPropertyChangeTracker(PropertyChangeTracker):
     # no out-point
     property_names = ["start", "duration", "in-point", "priority"]
 
+    def __init__(self):
+        PropertyChangeTracker.__init__(self)
+
     def connectToObject(self, obj):
         PropertyChangeTracker.connectToObject(self, obj)
         self.timeline = obj.timeline
@@ -47,9 +51,10 @@ class ClipPropertyChangeTracker(PropertyChangeTracker):
                 self._propertyChangedCb(self.obj, property_value, property_name)
 
 
-class KeyframeChangeTracker(Signallable):
-    __signals__ = {
-        "keyframe-moved": ["keyframe"]
+class KeyframeChangeTracker(GObject.Object):
+
+    __gsignals__ = {
+        "keyframe-moved": (GObject.SIGNAL_RUN_LAST, None, (object, object, object, object)),
     }
 
     def __init__(self):
@@ -91,7 +96,9 @@ class KeyframeChangeTracker(Signallable):
 
 
 class ClipPropertyChanged(UndoableAction):
+
     def __init__(self, clip, property_name, old_value, new_value):
+        UndoableAction.__init__(self)
         self.clip = clip
         self.property_name = property_name
         self.old_value = old_value
@@ -107,7 +114,9 @@ class ClipPropertyChanged(UndoableAction):
 
 
 class ClipAdded(UndoableAction):
+
     def __init__(self, layer, clip):
+        UndoableAction.__init__(self)
         self.layer = layer
         self.clip = clip
 
@@ -122,7 +131,9 @@ class ClipAdded(UndoableAction):
 
 
 class ClipRemoved(UndoableAction):
+
     def __init__(self, layer, clip):
+        UndoableAction.__init__(self)
         self.layer = layer
         self.clip = clip
 
@@ -137,7 +148,9 @@ class ClipRemoved(UndoableAction):
 
 
 class InterpolatorKeyframeAdded(UndoableAction):
+
     def __init__(self, track_element, keyframe):
+        UndoableAction.__init__(self)
         self.track_element = track_element
         self.keyframe = keyframe
 
@@ -151,7 +164,9 @@ class InterpolatorKeyframeAdded(UndoableAction):
 
 
 class InterpolatorKeyframeRemoved(UndoableAction):
+
     def __init__(self, track_element, keyframe):
+        UndoableAction.__init__(self)
         self.track_element = track_element
         self.keyframe = keyframe
 
@@ -166,7 +181,9 @@ class InterpolatorKeyframeRemoved(UndoableAction):
 
 
 class InterpolatorKeyframeChanged(UndoableAction):
+
     def __init__(self, track_element, keyframe, old_snapshot, new_snapshot):
+        UndoableAction.__init__(self)
         self.track_element = track_element
         self.keyframe = keyframe
         self.old_snapshot = old_snapshot
@@ -188,7 +205,9 @@ class InterpolatorKeyframeChanged(UndoableAction):
 
 
 class ActivePropertyChanged(UndoableAction):
+
     def __init__(self, effect_action, active):
+        UndoableAction.__init__(self)
         self.effect_action = effect_action
         self.active = not active
 
@@ -264,10 +283,10 @@ class TimelineLogObserver(object):
         tracker = ClipPropertyChangeTracker()
         tracker.connectToObject(clip)
         for property_name in tracker.property_names:
-            setattr(tracker, "last-%s" % property_name,
-                    clip.get_property(property_name))
-            tracker.connect("notify::" + property_name,
-                    self._clipPropertyChangedCb, property_name)
+            attr_name = "last-%s" % property_name
+            last_value = clip.get_property(property_name)
+            setattr(tracker, attr_name, last_value)
+        tracker.connect("monitored-property-changed", self._clipPropertyChangedCb)
         self.clip_property_trackers[clip] = tracker
 
         clip.connect("child-added", self._clipTrackElementAddedCb)
@@ -316,11 +335,13 @@ class TimelineLogObserver(object):
         self.log.push(action)
 
     def _clipPropertyChangedCb(self, tracker, clip,
-            old_value, new_value, property_name):
+            property_name, old_value, new_value):
+        attr_name = "last-%s" % property_name
         new_value = clip.get_property(property_name)
+        old_value = getattr(tracker, attr_name)
         action = self.timelinePropertyChangedAction(clip, property_name,
-                 getattr(tracker, "last-%s" % property_name), new_value)
-        setattr(tracker, "last-%s" % property_name, new_value)
+                 old_value, new_value)
+        setattr(tracker, attr_name, new_value)
         self.log.push(action)
 
     def _clipTrackElementAddedCb(self, clip, track_element):
diff --git a/pitivi/undo/undo.py b/pitivi/undo/undo.py
index 94f6a38..1c35d76 100644
--- a/pitivi/undo/undo.py
+++ b/pitivi/undo/undo.py
@@ -20,10 +20,11 @@
 # Boston, MA 02110-1301, USA.
 
 """
-Base classes for the undo/redo feature implementation
+Base classes for undo/redo.
 """
 
-from pitivi.utils.signal import Signallable
+from gi.repository import GObject
+
 from pitivi.utils.loggable import Loggable
 
 
@@ -37,17 +38,21 @@ class UndoWrongStateError(UndoError):
     pass
 
 
-class UndoableAction(Signallable):
+class UndoableAction(GObject.Object):
     """
-    This class represents an action that can be undone.
+    An action that can be undone.
     In other words, when your object's state changes, create an UndoableAction
     to allow reverting the change if needed later on.
     """
-    __signals__ = {
-        "done": [],
-        "undone": [],
+
+    __gsignals__ = {
+        "done": (GObject.SIGNAL_RUN_LAST, None, ()),
+        "undone": (GObject.SIGNAL_RUN_LAST, None, ()),
     }
 
+    def __init__(self):
+        GObject.Object.__init__(self)
+
     def do(self):
         raise NotImplementedError()
 
@@ -69,13 +74,13 @@ class UndoableActionStack(UndoableAction):
     """
     Simply a stack of UndoableAction objects.
     """
-    __signals__ = {
-        "done": [],
-        "undone": [],
-        "cleaned": [],
+
+    __gsignals__ = {
+        "cleaned": (GObject.SIGNAL_RUN_LAST, None, ()),
     }
 
     def __init__(self, action_group_name):
+        UndoableAction.__init__(self)
         self.action_group_name = action_group_name
         self.done_actions = []
         self.undone_actions = []
@@ -107,22 +112,23 @@ class UndoableActionStack(UndoableAction):
         self.emit("cleaned")
 
 
-class UndoableActionLog(Signallable, Loggable):
+class UndoableActionLog(GObject.Object, Loggable):
     """
     This is the "master" class that handles all the undo/redo system. There is
     only one instance of it in Pitivi: application.py's "action_log" property.
     """
-    __signals__ = {
-        "begin": ["stack", "nested"],
-        "push": ["stack", "action"],
-        "rollback": ["stack", "nested"],
-        "commit": ["stack", "nested"],
-        "undo": ["stack"],
-        "redo": ["stack"],
-        "cleaned": [],
+    __gsignals__ = {
+        "begin": (GObject.SIGNAL_RUN_LAST, None, (object, bool)),
+        "push": (GObject.SIGNAL_RUN_LAST, None, (object, object)),
+        "rollback": (GObject.SIGNAL_RUN_LAST, None, (object, bool)),
+        "commit": (GObject.SIGNAL_RUN_LAST, None, (object, bool)),
+        "undo": (GObject.SIGNAL_RUN_LAST, None, (object,)),
+        "redo": (GObject.SIGNAL_RUN_LAST, None, (object,)),
+        "cleaned": (GObject.SIGNAL_RUN_LAST, None, ()),
     }
 
     def __init__(self):
+        GObject.Object.__init__(self)
         Loggable.__init__(self)
 
         self.undo_stacks = []
@@ -256,28 +262,36 @@ class UndoableActionLog(Signallable, Loggable):
         return bool(len(self.stacks))
 
 
-class PropertyChangeTracker(Signallable):
+class PropertyChangeTracker(GObject.Object):
     """
     BaseClass to track a class property, Used for undo/redo
     """
-    __signals__ = {}
+
+    __gsignals__ = {
+        "monitored-property-changed": (GObject.SIGNAL_RUN_LAST, None, (object, str, object, object)),
+    }
+
+    # The properties monitored by this class
+    property_names = []
 
     def __init__(self):
+        GObject.Object.__init__(self)
         self.properties = {}
         self.obj = None
 
     def connectToObject(self, obj):
         self.obj = obj
         self.properties = self._takeCurrentSnapshot(obj)
+        # Connect to obj to keep track when the monitored properties
+        # are changed.
         for property_name in self.property_names:
-            signal_name = "notify::" + property_name
-            self.__signals__[signal_name] = []
-            obj.connect(signal_name,
-                    self._propertyChangedCb, property_name)
+            signal_name = "notify::%s" % property_name
+            obj.connect(signal_name, self._propertyChangedCb, property_name)
 
-    def _takeCurrentSnapshot(self, obj):
+    @classmethod
+    def _takeCurrentSnapshot(cls, obj):
         properties = {}
-        for property_name in self.property_names:
+        for property_name in cls.property_names:
             properties[property_name] = obj.get_property(property_name.replace("-", "_"))
 
         return properties
@@ -286,7 +300,7 @@ class PropertyChangeTracker(Signallable):
         self.obj = None
         obj.disconnect_by_func(self._propertyChangedCb)
 
-    def _propertyChangedCb(self, object, value, property_name):
+    def _propertyChangedCb(self, object, property_value, property_name):
         old_value = self.properties[property_name]
-        self.properties[property_name] = value
-        self.emit("notify::" + property_name, object, old_value, value)
+        self.properties[property_name] = property_value
+        self.emit("monitored-property-changed", object, property_name, old_value, property_value)
diff --git a/pitivi/utils/pipeline.py b/pitivi/utils/pipeline.py
index 77c625c..3200743 100644
--- a/pitivi/utils/pipeline.py
+++ b/pitivi/utils/pipeline.py
@@ -24,34 +24,44 @@
 """
 High-level pipelines
 """
-
 import platform
 
-from pitivi.utils.loggable import Loggable
-from pitivi.utils.signal import Signallable
-from pitivi.utils.misc import format_ns
 
 from gi.repository import GLib
 from gi.repository import GObject
 from gi.repository import Gst
 from gi.repository import GES
 
+from pitivi.utils.loggable import Loggable
+from pitivi.utils.misc import format_ns
+
+
 MAX_RECOVERIES = 5
 
+PIPELINE_SIGNALS = {
+    "state-change": (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_INT,)),
+    "position": (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_UINT64,)),
+    "duration-changed": (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_UINT64,)),
+    "eos": (GObject.SignalFlags.RUN_LAST, None, ()),
+    "error": (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_STRING, GObject.TYPE_STRING)),
+}
+
 
 class PipelineError(Exception):
     pass
 
 
-class Seeker(Signallable, Loggable):
+class Seeker(GObject.Object, Loggable):
     """
     The Seeker is a singleton helper class to do various seeking
     operations in the pipeline.
     """
+
     _instance = None
-    __signals__ = {
-        'seek': ['position', 'format'],
-        'seek-relative': ['time'],
+
+    __gsignals__ = {
+        "seek": (GObject.SIGNAL_RUN_LAST, None, (GObject.TYPE_UINT64, object)),
+        "seek-relative": (GObject.SIGNAL_RUN_LAST, None, (GObject.TYPE_INT64,)),
     }
 
     def __new__(cls, *args, **kwargs):
@@ -67,7 +77,7 @@ class Seeker(Signallable, Loggable):
         """
         @param timeout (optional): the amount of miliseconds for a seek attempt
         """
-        Signallable.__init__(self)
+        GObject.Object.__init__(self)
         Loggable.__init__(self)
 
         self.timeout = timeout
@@ -117,8 +127,10 @@ class Seeker(Signallable, Loggable):
 
             self._time = None
         elif self.position is not None and self.format is not None:
-            position, self.position = self.position, None
-            format, self.format = self.format, None
+            position = max(0, self.position)
+            self.position = None
+            format = self.format
+            self.format = None
             try:
                 self.emit('seek', position, format)
             except PipelineError as e:
@@ -135,7 +147,7 @@ class Seeker(Signallable, Loggable):
         return False
 
 
-class SimplePipeline(Signallable, Loggable):
+class SimplePipeline(GObject.Object, Loggable):
     """
     The Pipeline is only responsible for:
      - State changes
@@ -150,17 +162,11 @@ class SimplePipeline(Signallable, Loggable):
      - C{error} : An error happened.
     """
 
-    __signals__ = {
-        "state-change": ["state"],
-        "position": ["position"],
-        "duration-changed": ["duration"],
-        "eos": [],
-        "error": ["message", "details"]
-    }
+    __gsignals__ = PIPELINE_SIGNALS
 
     def __init__(self, pipeline):
+        GObject.Object.__init__(self)
         Loggable.__init__(self)
-        Signallable.__init__(self)
 
         self._pipeline = pipeline
         self._bus = self._pipeline.get_bus()
@@ -206,7 +212,8 @@ class SimplePipeline(Signallable, Loggable):
         self.pause()
         try:
             self.seekRelative(0)
-        except PipelineError:
+        except PipelineError as e:
+            self.warning("Could not flush because: %s", e)
             pass
 
     def setState(self, state):
@@ -255,8 +262,8 @@ class SimplePipeline(Signallable, Loggable):
         # during the playback.
         try:
             position = self.getPosition()
-        except PipelineError:
-            # Getting the position failed
+        except PipelineError as e:
+            self.warning("Getting the position failed: %s", e)
             return
         if position != Gst.CLOCK_TIME_NONE and position >= 0:
             self.emit("position", position)
@@ -344,12 +351,14 @@ class SimplePipeline(Signallable, Loggable):
 
     def _positionListenerCb(self):
         try:
-            cur = self.getPosition()
-            if cur != Gst.CLOCK_TIME_NONE:
-                self.emit('position', cur)
-                self.lastPosition = cur
-        except PipelineError:
-            pass
+            try:
+                position = self.getPosition()
+            except PipelineError as e:
+                self.warning("Could not get position because: %s", e)
+            else:
+                if position != Gst.CLOCK_TIME_NONE:
+                    self.emit('position', position)
+                    self.lastPosition = position
         finally:
             return True
 
@@ -435,7 +444,8 @@ class SimplePipeline(Signallable, Loggable):
                     # trigger duration-changed
                     try:
                         self.getDuration()
-                    except PipelineError:
+                    except PipelineError as e:
+                        self.warning("Could not get duration because: %s", e)
                         # no sinks??
                         pass
                     if self.pendingRecovery:
@@ -484,8 +494,8 @@ class SimplePipeline(Signallable, Loggable):
     def _queryDurationAsync(self, *unused_args, **unused_kwargs):
         try:
             self.getDuration()
-        except:
-            self.log("Duration failed... but we don't care")
+        except Exception as e:
+            self.warning("Could not get duration because: %s", e)
         return False
 
     def _handleErrorMessage(self, error, detail, source):
@@ -533,25 +543,9 @@ class Pipeline(GES.Pipeline, SimplePipeline):
     """
     Helper to handle GES.Pipeline through the SimplePipeline API
     and handle the Seeker properly
-
-    Signals:
-     - C{state-changed} : The state of the pipeline changed.
-     - C{position} : The current position of the pipeline changed.
-     - C{eos} : The Pipeline has finished playing.
-     - C{error} : An error happened.
     """
 
-    __gsignals__ = {
-        "state-change": (GObject.SignalFlags.RUN_LAST, None,
-                        (GObject.TYPE_INT,)),
-        "position": (GObject.SignalFlags.RUN_LAST, None,
-                        (GObject.TYPE_UINT64,)),
-        "duration-changed": (GObject.SignalFlags.RUN_LAST, None,
-                        (GObject.TYPE_UINT64,)),
-        "eos": (GObject.SignalFlags.RUN_LAST, None, ()),
-        "error": (GObject.SignalFlags.RUN_LAST, None,
-                (GObject.TYPE_STRING, GObject.TYPE_STRING))
-    }
+    __gsignals__ = PIPELINE_SIGNALS
 
     def __init__(self, pipeline=None):
         GES.Pipeline.__init__(self)
@@ -608,11 +602,5 @@ class Pipeline(GES.Pipeline, SimplePipeline):
                     new_pos / float(Gst.SECOND))
         self.simple_seek(new_pos)
 
-    def _seekCb(self, unused_ruler, position, unused_format):
-        """
-        The app's main seek method used when the user seeks manually.
-
-        We clamp the seeker position so that it cannot go past 0 or the
-        end of the timeline.
-        """
+    def _seekCb(self, unused_seeker, position, unused_format):
         self.simple_seek(position)
diff --git a/pitivi/utils/system.py b/pitivi/utils/system.py
index 4cd5651..e9af1bb 100644
--- a/pitivi/utils/system.py
+++ b/pitivi/utils/system.py
@@ -23,22 +23,24 @@ import multiprocessing
 import os
 import resource
 
+from gi.repository import GObject
+
 from pitivi.check import NOTIFY_SOFT_DEPENDENCY
 from pitivi.configure import APPNAME
 from pitivi.utils.loggable import Loggable
-from pitivi.utils.signal import Signallable
 
 
-class System(Signallable, Loggable):
-    """A base class for all *Systems
-    implementing methods available in other parts of Pitivi
+class System(GObject.Object, Loggable):
+    """
+    A base class for systems in which Pitivi runs.
     """
 
-    __signals__ = {
-        'update-power-inhibition': []
+    __gsignals__ = {
+        'update-power-inhibition': (GObject.SIGNAL_RUN_LAST, None, ()),
     }
 
     def __init__(self):
+        GObject.Object.__init__(self)
         Loggable.__init__(self)
         self.log("new object " + str(self))
         self._reset()
diff --git a/pitivi/utils/threads.py b/pitivi/utils/threads.py
index 9bd45a1..7e9912f 100644
--- a/pitivi/utils/threads.py
+++ b/pitivi/utils/threads.py
@@ -18,12 +18,11 @@
 # License along with this program; if not, write to the
 # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 # Boston, MA 02110-1301, USA.
-"""
-Threading support
-"""
 
 import threading
-from pitivi.utils.signal import Signallable
+
+from gi.repository import GObject
+
 from pitivi.utils.loggable import Loggable
 
 #
@@ -32,15 +31,17 @@ from pitivi.utils.loggable import Loggable
 #
 
 
-class Thread(threading.Thread, Signallable, Loggable):
+class Thread(threading.Thread, GObject.Object, Loggable):
     """
     Event-powered thread
     """
 
-    __signals__ = {
-        "done": None}
+    __gsignals__ = {
+        "done": (GObject.SIGNAL_RUN_LAST, None, ()),
+    }
 
     def __init__(self):
+        GObject.Object.__init__(self)
         threading.Thread.__init__(self)
         Loggable.__init__(self)
 
@@ -91,7 +92,7 @@ class ThreadMaster(Loggable):
         """ Stop all running Thread(s) controlled by this master """
         self.log("stopping all threads")
         joinedthreads = 0
-        while(joinedthreads < len(self.threads)):
+        while joinedthreads < len(self.threads):
             for thread in self.threads:
                 self.log("Trying to stop thread %r", thread)
                 try:
diff --git a/pitivi/utils/timeline.py b/pitivi/utils/timeline.py
index ddd3a8d..c21ba06 100644
--- a/pitivi/utils/timeline.py
+++ b/pitivi/utils/timeline.py
@@ -21,12 +21,9 @@
 # Boston, MA 02110-1301, USA.
 
 from gi.repository import GES
-from gi.repository import Gdk
+from gi.repository import GObject
 from gi.repository import Gst
 
-from pitivi.undo.undo import UndoableAction
-from pitivi.utils.signal import Signallable
-
 
 # Selection modes
 # Set the selection to the given set.
@@ -39,12 +36,13 @@ SELECT_ADD = 2
 
 #------------------------------------------------------------------------------#
 #                          Timeline Object management helper                   #
+
 class TimelineError(Exception):
     """Base Exception for errors happening in L{Timeline}s or L{Clip}s"""
     pass
 
 
-class Selected(Signallable):
+class Selected(GObject.Object):
     """
     A simple class that let us emit a selected-changed signal
     when needed, and that can be check directly to know if the
@@ -54,10 +52,12 @@ class Selected(Signallable):
     utils.timeline's "Selection" class.
     """
 
-    __signals__ = {
-        "selected-changed": []}
+    __gsignals__ = {
+        "selected-changed": (GObject.SIGNAL_RUN_LAST, None, (bool,)),
+    }
 
     def __init__(self):
+        GObject.Object.__init__(self)
         self._selected = False
 
     def __bool__(self):
@@ -77,7 +77,7 @@ class Selected(Signallable):
     selected = property(getSelected, setSelected)
 
 
-class Selection(Signallable):
+class Selection(GObject.Object):
     """
     A collection of L{GES.Clip}.
 
@@ -88,10 +88,12 @@ class Selection(Signallable):
     @type selected: C{list}
     """
 
-    __signals__ = {
-        "selection-changed": []}
+    __gsignals__ = {
+        "selection-changed": (GObject.SIGNAL_RUN_LAST, None, ()),
+    }
 
     def __init__(self):
+        GObject.Object.__init__(self)
         self.selected = set()
 
     def setToObj(self, obj, mode):
@@ -187,16 +189,17 @@ class Selection(Signallable):
 
 #-----------------------------------------------------------------------------#
 #                       Timeline edition modes helper                         #
-class EditingContext(Signallable):
+
+class EditingContext(GObject.Object):
     """
         Encapsulates interactive editing.
 
         This is the main class for interactive edition.
     """
 
-    __signals__ = {
-        "clip-trim": ["uri", "position"],
-        "clip-trim-finished": [],
+    __gsignals__ = {
+        "clip-trim": (GObject.SIGNAL_RUN_LAST, None, (GES.Clip, int)),
+        "clip-trim-finished": (GObject.SIGNAL_RUN_LAST, None, ()),
     }
 
     def __init__(self, focus, timeline, mode, edge, unused_settings, action_log):
@@ -222,8 +225,7 @@ class EditingContext(Signallable):
 
         @returns: An instance of L{pitivi.utils.timeline.EditingContext}
         """
-        Signallable.__init__(self)
-
+        GObject.Object.__init__(self)
         if isinstance(focus, GES.TrackElement):
             self.focus = focus.get_parent()
         else:
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 22265c6..63478af 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -13,7 +13,6 @@ tests =       \
        test_preset.py \
        test_project.py \
        test_projectsettings.py \
-       test_signallable.py \
        test_system.py \
        test_undo.py \
        test_undo_timeline.py \
diff --git a/tests/test_application.py b/tests/test_application.py
index 5c0fe26..62d8d56 100644
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -33,53 +33,48 @@ class MockGioFile(object):
 
 class TestPitivi(common.TestCase):
 
-    def testBasic(self):
-        app = application.Pitivi()
-        app.emit("startup")
-        self.assertTrue(app.shutdown())
-
     def testVersionInfo(self):
         app = application.Pitivi()
-        app.emit("startup")
+        app._checkVersion()
         self.assertTrue(app.isLatest())
 
         app = application.Pitivi()
-        app.emit("startup")
+        app._checkVersion()
         app._versionInfoReceivedCb(MockGioFile(), "invalid", None)
         self.assertTrue(app.isLatest())
 
         app = application.Pitivi()
-        app.emit("startup")
+        app._checkVersion()
         app._versionInfoReceivedCb(MockGioFile(), "%s=CURRENT" % configure.VERSION, None)
         self.assertTrue(app.isLatest())
         self.assertEqual(configure.VERSION, app.getLatest())
 
         app = application.Pitivi()
-        app.emit("startup")
+        app._checkVersion()
         app._versionInfoReceivedCb(MockGioFile(), "%s=current\n0=supported" % configure.VERSION, None)
         self.assertTrue(app.isLatest())
         self.assertEqual(configure.VERSION, app.getLatest())
 
         app = application.Pitivi()
-        app.emit("startup")
+        app._checkVersion()
         app._versionInfoReceivedCb(MockGioFile(), "999.0=CURRENT", None)
         self.assertFalse(app.isLatest())
         self.assertEqual("999.0", app.getLatest())
 
         app = application.Pitivi()
-        app.emit("startup")
+        app._checkVersion()
         app._versionInfoReceivedCb(MockGioFile(), "999.0=CURRENT\n%s=SUPPORTED" % configure.VERSION, None)
         self.assertFalse(app.isLatest())
         self.assertEqual("999.0", app.getLatest())
 
         app = application.Pitivi()
-        app.emit("startup")
+        app._checkVersion()
         app._versionInfoReceivedCb(MockGioFile(), "0.91=current", None)
         self.assertTrue(app.isLatest())
         self.assertEqual("0.91", app.getLatest())
 
         app = application.Pitivi()
-        app.emit("startup")
+        app._checkVersion()
         app._versionInfoReceivedCb(MockGioFile(), "0.100000000=current", None)
         self.assertFalse(app.isLatest())
         self.assertEqual("0.100000000", app.getLatest())
diff --git a/tests/test_project.py b/tests/test_project.py
index 8547e6f..a5ad911 100644
--- a/tests/test_project.py
+++ b/tests/test_project.py
@@ -28,18 +28,17 @@ from gi.repository import GES
 from gi.repository import GLib
 
 from pitivi.application import Pitivi
-from pitivi.project import Project, ProjectManager
+from pitivi.project import ProjectManager
 from pitivi.utils.misc import uri_is_reachable
 
 
 def _createRealProject(name=None):
     app = Pitivi()
-    app.emit("startup")
-    app.project_manager.newBlankProject()
+    project_manager = ProjectManager(app)
+    project_manager.newBlankProject()
     if name:
-        app.project_manager.current_project.name = name
-
-    return app.project_manager.current_project
+        project_manager.current_project.name = name
+    return project_manager.current_project
 
 
 class MockProject(object):
@@ -385,9 +384,6 @@ class TestProjectLoading(TestCase):
 class TestExportSettings(TestCase):
     """Test the project.MultimediaSettings class."""
 
-    def setUp(self):
-        self.project = _createRealProject()
-
     def testMasterAttributes(self):
         self._testMasterAttribute('muxer', dependant_attr='containersettings')
         self._testMasterAttribute('vencoder', dependant_attr='vcodecsettings')
@@ -395,33 +391,35 @@ class TestExportSettings(TestCase):
 
     def _testMasterAttribute(self, attr, dependant_attr):
         """Test changing the specified attr has effect on its dependant attr."""
+        project = _createRealProject()
+
         attr_value1 = "%s_value1" % attr
         attr_value2 = "%s_value2" % attr
 
-        setattr(self.project, attr, attr_value1)
-        setattr(self.project, dependant_attr, {})
-        getattr(self.project, dependant_attr)["key1"] = "v1"
-
-        setattr(self.project, attr, attr_value2)
-        setattr(self.project, dependant_attr, {})
-        getattr(self.project, dependant_attr)["key2"] = "v2"
-
-        setattr(self.project, attr, attr_value1)
-        self.assertTrue("key1" in getattr(self.project, dependant_attr))
-        self.assertFalse("key2" in getattr(self.project, dependant_attr))
-        self.assertEqual("v1", getattr(self.project, dependant_attr)["key1"])
-        setattr(self.project, dependant_attr, {})
-
-        setattr(self.project, attr, attr_value2)
-        self.assertFalse("key1" in getattr(self.project, dependant_attr))
-        self.assertTrue("key2" in getattr(self.project, dependant_attr))
-        self.assertEqual("v2", getattr(self.project, dependant_attr)["key2"])
-        setattr(self.project, dependant_attr, {})
-
-        setattr(self.project, attr, attr_value1)
-        self.assertFalse("key1" in getattr(self.project, dependant_attr))
-        self.assertFalse("key2" in getattr(self.project, dependant_attr))
-
-        setattr(self.project, attr, attr_value2)
-        self.assertFalse("key1" in getattr(self.project, dependant_attr))
-        self.assertFalse("key2" in getattr(self.project, dependant_attr))
+        setattr(project, attr, attr_value1)
+        setattr(project, dependant_attr, {})
+        getattr(project, dependant_attr)["key1"] = "v1"
+
+        setattr(project, attr, attr_value2)
+        setattr(project, dependant_attr, {})
+        getattr(project, dependant_attr)["key2"] = "v2"
+
+        setattr(project, attr, attr_value1)
+        self.assertTrue("key1" in getattr(project, dependant_attr))
+        self.assertFalse("key2" in getattr(project, dependant_attr))
+        self.assertEqual("v1", getattr(project, dependant_attr)["key1"])
+        setattr(project, dependant_attr, {})
+
+        setattr(project, attr, attr_value2)
+        self.assertFalse("key1" in getattr(project, dependant_attr))
+        self.assertTrue("key2" in getattr(project, dependant_attr))
+        self.assertEqual("v2", getattr(project, dependant_attr)["key2"])
+        setattr(project, dependant_attr, {})
+
+        setattr(project, attr, attr_value1)
+        self.assertFalse("key1" in getattr(project, dependant_attr))
+        self.assertFalse("key2" in getattr(project, dependant_attr))
+
+        setattr(project, attr, attr_value2)
+        self.assertFalse("key1" in getattr(project, dependant_attr))
+        self.assertFalse("key2" in getattr(project, dependant_attr))
diff --git a/tests/test_undo.py b/tests/test_undo.py
index cec82db..6199a5a 100644
--- a/tests/test_undo.py
+++ b/tests/test_undo.py
@@ -28,6 +28,9 @@ from pitivi.undo.undo import UndoError, UndoWrongStateError, UndoableAction, \
 class DummyUndoableAction(UndoableAction):
     done_ = True
 
+    def __init__(self):
+        UndoableAction.__init__(self)
+
     def do(self):
         self.done_ = True
         self._done()
@@ -392,6 +395,7 @@ class TestUndoableActionLog(TestCase):
 
         class Action(UndoableAction):
             def __init__(self, n):
+                UndoableAction.__init__(self)
                 self.n = n
 
             def do(self):


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