Improve resize/co-dragging GTK
authorH.G.Muller <hgm@hgm-xboard.(none)>
Mon, 11 Apr 2016 18:44:27 +0000 (20:44 +0200)
committerH.G.Muller <hgm@hgm-xboard.(none)>
Sun, 17 Apr 2016 08:24:59 +0000 (10:24 +0200)
The reconfigure event of the main board is not processed directly,
but sets a timeout to call the actual handler, which will be restarted
when new reconfigure events occur during the timeout period. This makes
that the (very timeconsuming) redrawing and moving of all windows
will only be done if the stream of events dries up.
  Unfortunately the ReSize routine called as part of the handling needs
to be interruptable, which can cause recursive calling of the reconfigure
handler. A variable 'busy' would ignore such recursion, but at the price
of missing the interrupting event completely. The attempted fix to set
a new timeout was flawed, as delayedDragTag would not have been cleared
at that point. So we threw it out. Now 'busy' is a counter, which will
remember if there were ignored recursion attempts, and then makes these
into a harmless tail recursion, to do the resize/drag once more, based
on the latest window parameters.

gtk/xboard.c

index 96889c8..5ad75b1 100644 (file)
@@ -1759,18 +1759,19 @@ static guint delayedDragTag = 0;
 void
 DragProc ()
 {
-       static int busy;
-       if(busy) { // prevent recursive calling, but postpone interrupting call rather than lose it
-           if(!delayedDragTag) delayedDragTag = g_timeout_add( 200, (GSourceFunc) DragProc, NULL);
-           return;
-       }
-       busy = 1;
+    static int busy;
+    if(busy++) return; // prevent recursive calling, but remember we missed an event in 'busy'
+
+    if(delayedDragTag) g_source_remove(delayedDragTag); // no more timer interrupts from same event!
+    delayedDragTag = 0;
+
+    do {
        GetActualPlacement(shellWidget, &wpNew);
        if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
           wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
-           busy = 0; return; // false alarm
+           busy = 0; break; // false alarm
        }
-       ReSize(&wpNew);
+       ReSize(&wpNew); // this can be interrupted by other events
        if(appData.useStickyWindows) {
            if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
            if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
@@ -1780,9 +1781,8 @@ DragProc ()
         }
        wpMain = wpNew;
        DrawPosition(True, NULL);
-       if(delayedDragTag) g_source_remove(delayedDragTag);
-       delayedDragTag = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
-       busy = 0;
+       if(busy > 2) busy = 2; // if multiple events were backlogged, only do one more
+    } while(--busy);
 }
 
 void