Commits

Adrian Buehlmann committed 69ba8d0

shellext: invent "peek" state for overlays

If a file was edited, saved and then the edit undone and saved again, the
overlay for that file was stuck at "modified" until the user manually
triggered an "Update icons" or caused a "hg status".

Fixed by inventing a new "peek" state ('P') which causes an update of
.hg/dirstate via TortoiseHgOverlayServer. A file X is considered to be in
peek state, if the size of X and its size in the dirstate are the same but
the mtimes are different. This requires a look into the file contents to
tell if the file really has changed or not.

Note that Thgstatus::update() is now called with path (instead of cur.hgroot)
so that shell notifications are done for the affected file.

Comments (0)

Files changed (2)

win32/shellext/Direntry.cpp

     switch (this->state)
     {
     case 'n':
-        if (this->mtime == (unsigned)stat.mtime
-            && this->size == (unsigned)stat.size
-            )
-            return 'C';
-        else
-            return 'M';
+        if (this->size != (unsigned)stat.size)
+            return 'M'; // modified
+        if (this->mtime == (unsigned)stat.mtime)
+            return 'C'; // clean
+        return 'P'; // must peek into file contents
     case 'm':
         return 'M';
     case 'r':

win32/shellext/QueryDirstate.cpp

     if (!outdated && last.path == path) 
     {
         outStatus = last.status;
+        if (outStatus == 'P')
+            outStatus = 'M';
         return 1;
     }
 
 
     outStatus = e->status(stat);
 
-    if (outStatus == 'M' && pdirsta)
+    if (unset)
+        goto exit;
+
+    bool update = false;
+
+    if (outStatus == 'M')
     {
         std::string relbase;
-        if (get_relpath(cur.hgroot, cur.basedir, relbase))
+        if (pdirsta && get_relpath(cur.hgroot, cur.basedir, relbase))
         {
             TDEBUG_TRACE(dp << "relbase = '" << relbase << "'");
 
             TDEBUG_TRACE(dp << "basedir_status = " << basedir_status);
 
             if (basedir_status != 'M')
-            {
-                if (unset)
-                {
-                    TDEBUG_TRACE(dp << "omitting Thgstatus::update");
-                }
-                else
-                {
-                    TDEBUG_TRACE(dp << "calling Thgstatus::update");
-                    Thgstatus::update(cur.hgroot);
-                }
-            }
+                update = true;
+        }        
+    }
+    else if (outStatus == 'P')
+    {
+        static unsigned lasttickcount;
+
+        const unsigned tc = ::GetTickCount();
+        const bool outdated = tc - lasttickcount > 6000;
+
+        if (outdated) // protect against endless update loops
+        {
+            update = true;
+            lasttickcount = tc;
         }
+
+        TDEBUG_TRACE(dp << "outStatus is 'P'");
     }
 
+    if (update)
+    {
+        TDEBUG_TRACE(dp << "calling Thgstatus::update");
+        Thgstatus::update(path);
+    }
+
+  exit:
     cur.status = outStatus;
+    if (outStatus == 'P')
+        outStatus = 'M';
     cur.tickcount = ::GetTickCount();
     last = cur;
     return 1;