[meld] filediff: Add a new callback locking helper and use for scrolling



commit 854e79d732f8b0819ab392b81fa3954858d9339b
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Mon Apr 17 08:52:01 2017 +1000

    filediff: Add a new callback locking helper and use for scrolling
    
    The main benefit of this, other than looking nicer in use, is that we're
    doing our locking in a try/finally, so tracebacks in the scrolling code
    won't leave us with a permanently held scroll lock.

 meld/filediff.py |   39 +++++++++++++++++++++++++++++----------
 1 files changed, 29 insertions(+), 10 deletions(-)
---
diff --git a/meld/filediff.py b/meld/filediff.py
index 8a8c877..10d3e19 100644
--- a/meld/filediff.py
+++ b/meld/filediff.py
@@ -54,6 +54,33 @@ def with_focused_pane(function):
     return wrap_function
 
 
+def with_scroll_lock(lock_attr):
+    """Decorator for locking a callback based on an instance attribute
+
+    This is used when scrolling panes. Since a scroll event in one pane
+    causes us to set the scroll position in other panes, we need to
+    stop these other panes re-scrolling the initial one.
+
+    Unlike a threading-style lock, this decorator discards any calls
+    that occur while the lock is held, rather than queuing them.
+
+    :param lock_attr: The instance attribute used to lock access
+    """
+    def wrap(function):
+        @functools.wraps(function)
+        def wrap_function(locked, *args, **kwargs):
+            if getattr(locked, lock_attr, False) or locked._scroll_lock:
+                return
+
+            try:
+                setattr(locked, lock_attr, True)
+                return function(locked, *args, **kwargs)
+            finally:
+                setattr(locked, lock_attr, False)
+        return wrap_function
+    return wrap
+
+
 MASK_SHIFT, MASK_CTRL = 1, 2
 PANE_LEFT, PANE_RIGHT = -1, +1
 
@@ -1633,23 +1660,16 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         buf = self.textbuffer[index]
         self.set_buffer_editable(buf, not button.get_active())
 
+    @with_scroll_lock('_sync_hscroll_lock')
     def _sync_hscroll(self, adjustment):
-        if self._sync_hscroll_lock or self._scroll_lock:
-            return
-
-        self._sync_hscroll_lock = True
         val = adjustment.get_value()
         for sw in self.scrolledwindow[:self.num_panes]:
             adj = sw.get_hadjustment()
             if adj is not adjustment:
                 adj.set_value(val)
-        self._sync_hscroll_lock = False
 
+    @with_scroll_lock('_sync_vscroll_lock')
     def _sync_vscroll(self, adjustment, master):
-        if self._sync_vscroll_lock or self._scroll_lock:
-            return
-
-        self._sync_vscroll_lock = True
         SYNCPOINT = 0.5
 
         # Middle of the screen, in buffer coords
@@ -1715,7 +1735,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             # If we just changed the central bar, make it the master
             if i == 1:
                 master, target_line = 1, other_line
-        self._sync_vscroll_lock = False
 
         for lm in self.linkmap:
             lm.queue_draw()


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