From d600f18d5e7509695c3e4b2eaac69dec84c7ce17 Mon Sep 17 00:00:00 2001
From: Georg Koppen <g.koppen@jondos.de>
Date: Fri, 31 May 2013 12:24:19 +0200
Subject: [PATCH] fix for bug 8478 which a) moves the resizing logic to
 |onStateChange()| of a nsIWebProgressListener as this is
 closer to the xul-window-visible notification which avoids
 race conditions and b) chooses a x16 part of the toolbar
 icons as this prevents a resizing of the content window
 height on Windos due to non 16x16 icons

---
 src/chrome/content/torbutton.js |  172 +++++++++++++++------------------------
 src/chrome/skin/torbutton.css   |    9 ++
 2 files changed, 76 insertions(+), 105 deletions(-)

diff --git a/src/chrome/content/torbutton.js b/src/chrome/content/torbutton.js
index 12660d7..d5e2f34 100644
--- a/src/chrome/content/torbutton.js
+++ b/src/chrome/content/torbutton.js
@@ -2253,14 +2253,6 @@ function torbutton_do_main_window_startup()
     torbutton_log(3, "Torbutton main window startup");
     m_tb_is_main_window = true;
 
-    // http://www.xulplanet.com/references/xpcomref/ifaces/nsIWebProgress.html
-    var progress =
-        Components.classes["@mozilla.org/docloaderservice;1"].
-        getService(Components.interfaces.nsIWebProgress);
-
-    progress.addProgressListener(torbutton_weblistener,
-            Components.interfaces.nsIWebProgress.NOTIFY_LOCATION);
-
     // Wrap Google search service.
     //torbutton_wrap_search_service();
 
@@ -2370,60 +2362,6 @@ function torbutton_is_windowed(wind) {
     return true;
 }
 
-// Bug 1506 P1/P3: Setting a fixed window size is important, but
-// probably not for android.
-function torbutton_set_window_size(bWin) {
-    if (!bWin || typeof(bWin) == "undefined") {
-        torbutton_log(5, "No initial browser content window?");
-        return;
-    }
-
-    if (m_tb_prefs.getBoolPref("extensions.torbutton.resize_new_windows")
-            && m_tb_prefs.getBoolPref("extensions.torbutton.tor_enabled")
-            && torbutton_is_windowed(window)) {
-        var screenMan = Components.classes["@mozilla.org/gfx/screenmanager;1"]
-                            .getService(Components.interfaces.nsIScreenManager);
-        var junk = {}, availWidth = {}, availHeight = {};
-        screenMan.primaryScreen.GetRect(junk, junk, availWidth, availHeight);
-
-        // We need to set the inner width to an initial value because it has none
-        // at this point...
-        bWin.innerWidth = 200;
-        bWin.innerHeight = 200;
-
-        // XXX: This is sufficient to prevent some kind of weird resize race condition on Linux.
-        // Why or how, you ask? I have no fucking clue, man.
-        if (bWin.innerWidth != 200 || bWin.innerHeight != 200) {
-            bWin.innerHeight = 200;
-            bWin.innerWidth = 200;
-        }
-        torbutton_log(3, "About to resize new window: "+window.outerWidth+"x"+window.outerHeight
-                +" inner: "+bWin.innerWidth+"x"+bWin.innerHeight+
-                " in state "+window.windowState+" Have "+availWidth.value+"x"+availHeight.value);
-
-        var maxHeight = availHeight.value - (window.outerHeight - bWin.innerHeight) - 51;
-        var maxWidth = availWidth.value - (window.outerWidth - bWin.innerWidth);
-        
-        torbutton_log(3, "Got max dimensions: "+maxWidth+"x"+maxHeight);
-
-        var width;
-        var height;
-
-        if (maxWidth > 1000) {
-            width = 1000;
-        } else {
-            width = Math.floor(maxWidth/200.0)*200;
-        }
-
-        height = Math.floor(maxHeight/100.0)*100;
-
-        // This is fun. any attempt to directly set the inner window actually resizes the outer width
-        // to that value instead. Must use resizeBy() instead of assignment or resizeTo()
-        bWin.resizeBy(width-bWin.innerWidth,height-bWin.innerHeight);
-        torbutton_log(3, "Resized new window from: "+bWin.innerWidth+"x"+bWin.innerHeight+" to "+width+"x"+height+" in state "+window.windowState);
-    }
-}
-
 // Bug 1506 P3: This is needed pretty much only for the version check
 // and the window resizing. See comments for individual functions for
 // details
@@ -2448,7 +2386,14 @@ function torbutton_new_window(event)
 
     torbutton_do_startup();
 
-    torbutton_set_window_size(browser.contentWindow);
+    if (m_tb_prefs.getBoolPref("extensions.torbutton.resize_new_windows")
+            && m_tb_prefs.getBoolPref("extensions.torbutton.tor_enabled")
+            && torbutton_is_windowed(window)) {
+      var progress = Cc["@mozilla.org/docloaderservice;1"].getService(Ci.
+        nsIWebProgress);
+      progress.addProgressListener(torbutton_resizelistener,
+        Components.interfaces.nsIWebProgress.NOTIFY_STATE_ALL);
+    }
 
     // Check the version on every new window. We're already pinging check in these cases.    
     torbutton_do_async_versioncheck();
@@ -2482,11 +2427,6 @@ function torbutton_close_window(event) {
             }
         }
 
-        // remove old listeners
-        var progress = Components.classes["@mozilla.org/docloaderservice;1"].
-            getService(Components.interfaces.nsIWebProgress);
-
-        progress.removeProgressListener(torbutton_weblistener);
         torbutton_unique_pref_observer.unregister();
 
         // XXX: We should fold this into our code..
@@ -2619,14 +2559,9 @@ function torbutton_check_progress(aProgress, aRequest, aFlags, new_loc) {
     return 0;
 }
 
-// Warning: These can also fire when the 'debuglogger' extension
-// updates its window. Typically for this, doc.domain is null. Do not
-// log in this case (until we find a better way to filter those
-// events out). Use torbutton_eclog for common-path stuff.]
-// 
-// Bug 1506 P0: This listener is for blocking plugins and installing JS hooks.
-// It can be eliminated.
-var torbutton_weblistener =
+// Bug 1506 P1/P3: Setting a fixed window size is important, but
+// probably not for android.
+var torbutton_resizelistener =
 {
   QueryInterface: function(aIID)
   {
@@ -2637,40 +2572,67 @@ var torbutton_weblistener =
    throw Components.results.NS_NOINTERFACE;
   },
 
-  onLocationChange: function(aProgress, aRequest, aURI)
-  {
-      torbutton_eclog(2, 'onLocationChange: '+aURI.asciiSpec);
-      if(aURI.scheme == "about" || aURI.scheme == "chrome") {
-          torbutton_eclog(3, "Skipping location change for "+aURI.asciiSpec);
+  onLocationChange: function(aProgress, aRequest, aURI) {},
+  onStateChange: function(aProgress, aRequest, aFlag, aStatus) {
+    if (aFlag & Components.interfaces.nsIWebProgressListener.STATE_STOP) {
+      var progress =
+        Components.classes["@mozilla.org/docloaderservice;1"].
+        getService(Components.interfaces.nsIWebProgress);
+      var win = getBrowser().contentWindow;
+      if (!win || typeof(win) == "undefined") {
+        torbutton_log(5, "No initial browser content window?");
+        progress.removeProgressListener(this);
+        return;
+      }
+      var screenMan = Components.classes["@mozilla.org/gfx/screenmanager;1"].
+        getService(Components.interfaces.nsIScreenManager);
+      var junk = {}, availWidth = {}, availHeight = {};
+      screenMan.primaryScreen.GetRect(junk, junk, availWidth, availHeight);
+
+      // We need to set the inner width to an initial value because it has none
+      // at this point... Choosing "300" as this works even on Windows
+      // reliably.
+      win.innerWidth = 300;
+      win.innerHeight = 300;
+
+      torbutton_log(3, "About to resize new window: " + window.outerWidth +
+        "x" + window.outerHeight + " inner: " + win.innerWidth + "x" + win.
+        innerHeight + " in state " + window.windowState + " Have " +
+        availWidth.value + "x" + availHeight.value);
+
+      var maxHeight = availHeight.value -
+        (window.outerHeight - win.innerHeight) - 51;
+      var maxWidth = availWidth.value - (window.outerWidth - win.innerWidth);
+      torbutton_log(3, "Got max dimensions: " + maxWidth + "x" + maxHeight);
+
+      var width;
+      var height;
+
+      if (maxWidth > 1000) {
+        width = 1000;
       } else {
-          return torbutton_check_progress(aProgress, aRequest, 0, true);
+        width = Math.floor(maxWidth/200.0)*200;
       }
-  },
 
-  // XXX: The following can probably go
-  onStateChange: function(aProgress, aRequest, aFlag, aStatus)
-  { 
-      torbutton_eclog(2, 'State change()');
-      return torbutton_check_progress(aProgress, aRequest, aFlag, false);
-  },
+      height = Math.floor(maxHeight/100.0)*100;
 
-  onProgressChange: function(aProgress, aRequest, curSelfProgress, maxSelfProgress, curTotalProgress, maxTotalProgress) 
-  { 
-      torbutton_eclog(2, 'called progressChange'); 
-      return torbutton_check_progress(aProgress, aRequest, 0, false);
-  },
-  
-  onStatusChange: function(aProgress, aRequest, stat, message) 
-  { 
-      torbutton_eclog(2, 'called progressChange'); 
-      return torbutton_check_progress(aProgress, aRequest, 0, false);
+      // This is fun. any attempt to directly set the inner window actually
+      // resizes the outer width to that value instead. Must use resizeBy()
+      // instead of assignment or resizeTo()
+      win.resizeBy(width - win.innerWidth, height - win.innerHeight);
+      torbutton_log(3, "Resized new window from: " + win.innerWidth + "x" +
+        win.innerHeight + " to " + width + "x" + height + " in state " +
+        window.windowState);
+
+      progress.removeProgressListener(this);
+    }
   },
-  
-  onSecurityChange: function() {return 0;},
-  
-  onLinkIconAvailable: function() 
-  { /*torbutton_eclog(1, 'called linkIcon'); */ return 0; }
-}
 
+  onProgressChange: function(aProgress, aRequest, curSelfProgress,
+                             maxSelfProgress, curTotalProgress,
+                             maxTotalProgress) {},
+  onStatusChange: function(aProgress, aRequest, stat, message) {},
+  onSecurityChange: function() {}
+};
 
 //vim:set ts=4
diff --git a/src/chrome/skin/torbutton.css b/src/chrome/skin/torbutton.css
index 2218e9f..ce59cc9 100644
--- a/src/chrome/skin/torbutton.css
+++ b/src/chrome/skin/torbutton.css
@@ -13,14 +13,23 @@
 toolbar[iconsize="small"] #torbutton-button {
   list-style-image: url("chrome://torbutton/skin/tor-16.png");
 }
+// Although the tor-enabled-16.png, tor-disabled-16.png and tor-update-16.gif
+// indicate that they are 16x16 icons, they have 18x18 pixels in fact. This
+// leads to resizing the content window's height on start-up on Windows at
+// least. To guarantee a content window with a multiple of 200x100 we
+// therefore use only a x16 part of each icon while trying to minimize bad UI
+// effects until #8941 gets fixed.
 toolbar[iconsize="small"] #torbutton-button[tbstatus="on"] {
   list-style-image: url("chrome://torbutton/skin/tor-enabled-16.png");
+  -moz-image-region: rect(1px, 17px, 17px, 1px);
 }
 toolbar[iconsize="small"] #torbutton-button[tbstatus="off"] {
   list-style-image: url("chrome://torbutton/skin/tor-disabled-16.png");
+  -moz-image-region: rect(0px, 18px, 16px, 0px);
 }
 toolbar[iconsize="small"] #torbutton-button[tbUpdateNeeded="true"] {
   list-style-image: url("chrome://torbutton/skin/tor-update-16.gif");
+  -moz-image-region: rect(1px, 17px, 17px, 1px);
 }
 
 #torbutton-panel {
-- 
1.7.10.4

