[Pkg-mozext-commits] [tree-style-tab] 01/03: Imported Upstream version 0.16.2015111001

Ximin Luo infinity0 at debian.org
Fri Nov 13 16:11:46 UTC 2015


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch master
in repository tree-style-tab.

commit b01574386940bd498c576024849d74cd6264329d
Author: Ximin Luo <infinity0 at debian.org>
Date:   Fri Nov 13 00:20:00 2015 +0100

    Imported Upstream version 0.16.2015111001
---
 META-INF/manifest.mf                               | 138 +++---
 META-INF/mozilla.rsa                               | Bin 4189 -> 4189 bytes
 META-INF/mozilla.sf                                |   4 +-
 content/treestyletab/bookmarksOverlay.js           |   7 +
 content/treestyletab/bookmarksOverlayEditable.js   |   3 +
 content/treestyletab/content-utils.js              |  55 +++
 content/treestyletab/res/bookmarkMultipleTabs.xul  |   7 +-
 ...kmarkMultipleTabs_bookmarkPropertiesOverlay.xul |  45 +-
 content/treestyletab/res/tabsDragUtils.js          |  55 ++-
 content/treestyletab/treestyletab.css              |  45 +-
 content/treestyletab/treestyletab.js               |   6 +
 content/treestyletab/windowHelper.js               | 546 +++++++++++----------
 content/treestyletab/windowHelperHacks.js          |  56 ++-
 defaults/preferences/treestyletab.js               |  12 +-
 install.rdf                                        |   4 +-
 locale/en-US/treestyletab/treestyletab.dtd         |   4 +-
 modules/ReferenceCounter.js                        |  42 ++
 modules/autoHide.js                                | 123 ++++-
 modules/base.js                                    |  47 +-
 modules/browser.js                                 | 484 +++++++++---------
 modules/browserUIShowHideObserver.js               | 134 +++--
 modules/constants.js                               |   9 +-
 modules/contentBridge.js                           |  21 +-
 modules/fullTooltip.js                             |   2 +-
 modules/fullscreenObserver.js                      |  21 +-
 modules/groupTab.js                                |   2 +-
 modules/lib/inherit.jsm                            |   2 +-
 modules/pseudoTreeBuilder.js                       |   2 +-
 modules/tabAttributesObserver.js                   |   2 +-
 modules/tabbarDNDObserver.js                       | 150 ++++--
 modules/tabpanelDNDObserver.js                     |   9 +-
 modules/themeManager.js                            |   2 +-
 modules/utils.js                                   |  70 ++-
 modules/window.js                                  | 200 +++++---
 skin/classic/treestyletab/Linux-base.css           |   6 +
 skin/classic/treestyletab/square/tab-surface.css   |   4 +-
 skin/classic/treestyletab/ui-base.css              |  34 +-
 37 files changed, 1477 insertions(+), 876 deletions(-)

diff --git a/META-INF/manifest.mf b/META-INF/manifest.mf
index 8cd9d38..2264eab 100644
--- a/META-INF/manifest.mf
+++ b/META-INF/manifest.mf
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
 
 Name: install.rdf
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: XmdqNUkTM6QdwsQ5YvcjPw==
-SHA1-Digest: YAn17jTjifr/5uDzOWuTMkgbS24=
+MD5-Digest: LU9MOfmVFQKCFVg0AM159g==
+SHA1-Digest: BNsWVAkBeLoD+KiFzhm8uZhdrf0=
 
 Name: chrome.manifest
 Digest-Algorithms: MD5 SHA1
@@ -22,8 +22,8 @@ SHA1-Digest: XLM7zjvCkIi09SoAGOVOZdeQofY=
 
 Name: content/treestyletab/bookmarksOverlay.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: a1UScbFacLdf3bGkQHgZVg==
-SHA1-Digest: akG9SMpPnjkZ2aci1msbsa34ymc=
+MD5-Digest: sLs6Xz86OV6NK6RJVHgEvA==
+SHA1-Digest: pmX3AWu0z9RzIeDgImy8NfP1UIA=
 
 Name: content/treestyletab/bookmarksOverlay.xul
 Digest-Algorithms: MD5 SHA1
@@ -37,8 +37,8 @@ SHA1-Digest: /V6d117O8c9Qgt7NoCuVRN2bOF0=
 
 Name: content/treestyletab/bookmarksOverlayEditable.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 1OUCn+P21t3cQaO4Zjc3fw==
-SHA1-Digest: LMw7a9VHhMRD5D+gBKwYQBNQjWE=
+MD5-Digest: fz/WG9plX7+4mymO1k4eqg==
+SHA1-Digest: CBTSfQAfKiL/sT9YpY8vwW9Zml0=
 
 Name: content/treestyletab/bookmarksOverlayEditable.xul
 Digest-Algorithms: MD5 SHA1
@@ -65,6 +65,11 @@ Digest-Algorithms: MD5 SHA1
 MD5-Digest: 5LerXpT+fFUV2k1YOWLOCw==
 SHA1-Digest: UoiQ5kghSuZB2O1NOtmcO82G6ZY=
 
+Name: content/treestyletab/content-utils.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: u5TSTFqsmy3oW+pn6MvYGQ==
+SHA1-Digest: XPRa16z/xWO9CPGCemcNYgi2Lwk=
+
 Name: content/treestyletab/group.xul
 Digest-Algorithms: MD5 SHA1
 MD5-Digest: 36AhehtnHOpGrElzTkAIzQ==
@@ -92,13 +97,13 @@ SHA1-Digest: dUnh9cVls70LC0cO+AzOTyJ+7Bc=
 
 Name: content/treestyletab/treestyletab.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: ckNWCVVeVUwyAE8Ks4gRgA==
-SHA1-Digest: BmB3htcfoWnSKj7KE5BB7Cu9Sec=
+MD5-Digest: UIzT5sgWVHFZhuXzoCT9cQ==
+SHA1-Digest: eYWjBJvS12pO+j90U4BIpE9BDvo=
 
 Name: content/treestyletab/treestyletab.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: ld2sTGlJa+As/xraL/CwOQ==
-SHA1-Digest: LA2MSt95ft6Mt7ufc53o/qq0oew=
+MD5-Digest: rAQdu8NF3MYvlInTA/rnZA==
+SHA1-Digest: mdGLj3IkGat9NH80/KPUwZIx3zc=
 
 Name: content/treestyletab/treestyletab.xml
 Digest-Algorithms: MD5 SHA1
@@ -112,24 +117,24 @@ SHA1-Digest: UL5BD1Q3QU5lrlyvVrvvYzxKzpM=
 
 Name: content/treestyletab/windowHelper.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: jNbQDZNTag3AkbZ5qUfYmA==
-SHA1-Digest: C/mp3RdS4rQjkmrKZNS8X0Nly7I=
+MD5-Digest: djwD/HnGMfG+uyywHjuBnQ==
+SHA1-Digest: NIayIo0Ik7UxA9Gh2Kt/86y6tmI=
 
 Name: content/treestyletab/windowHelperHacks.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: +s/LgIomma9/3/NXA4xK1Q==
-SHA1-Digest: rAB+c6L9HAPpCxWS5vcbvorWmNk=
+MD5-Digest: HU2bYPiXZtwNdiUbkepXhA==
+SHA1-Digest: RJmFgfQwbq0H5AO7AjH42biwkT4=
 
 Name: content/treestyletab/res/bookmarkMultipleTabs.xul
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: BxexkR9ZJCUNcfDfbTeB+Q==
-SHA1-Digest: 60fRvXNQIxZszW6dVBK8RGi/StQ=
+MD5-Digest: iebNA+/X3W4H8iz0vn/JyQ==
+SHA1-Digest: SIpJbMdGhMrFhN3F1Bg6yykW/oQ=
 
 Name: content/treestyletab/res/bookmarkMultipleTabs_bookmarkPropertiesOv
  erlay.xul
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: hn+GVG2KuEdIcR6cd+cPVg==
-SHA1-Digest: zvKA9WdbSHU79zF+CwuH41FYeyU=
+MD5-Digest: hLKdeMp53y13zIADzK90pw==
+SHA1-Digest: egqUV8t6VkSTKSNKgj1ZC+yc3jQ=
 
 Name: content/treestyletab/res/icon.png
 Digest-Algorithms: MD5 SHA1
@@ -173,8 +178,8 @@ SHA1-Digest: WzGw9OlK27u2qgwpylJvL+GMB9k=
 
 Name: content/treestyletab/res/tabsDragUtils.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: HiAUx9j5fAnkXeYyqQsnTQ==
-SHA1-Digest: GcN7PicYjUYq8jnq5FsdCfJXOvA=
+MD5-Digest: W9TDKDIlBGpERagCv9lS9A==
+SHA1-Digest: UDF3Oxyej6oju457n513VqAIt88=
 
 Name: content/treestyletab/res/twisty-modern-b.png
 Digest-Algorithms: MD5 SHA1
@@ -198,8 +203,8 @@ SHA1-Digest: q0mYa40sk7KoHzdmK6voR/OuGF8=
 
 Name: defaults/preferences/treestyletab.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 9biMjtnraI40dhAz4IJYYg==
-SHA1-Digest: MkVnqunBxYKr7c8ZcQQ9B0CDcDA=
+MD5-Digest: AdO/+hHOi1b60QOLzwVY+g==
+SHA1-Digest: e+5nkclUxU2r/6DOyrc4Wp20/ww=
 
 Name: locale/cs/treestyletab/license.txt
 Digest-Algorithms: MD5 SHA1
@@ -253,8 +258,8 @@ SHA1-Digest: /vNGGzRR58QK5AOQjlorkE5GCAI=
 
 Name: locale/en-US/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: ldc81dCNxvzqLjJSmCOTNg==
-SHA1-Digest: suzdF/d1DEkJBDpvaRjChgHD/Ew=
+MD5-Digest: zYzWcmQTBKdgXDyHSLHevQ==
+SHA1-Digest: H3VKEtaRrs9Jt9dPBpdZkTePgKg=
 
 Name: locale/en-US/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -398,83 +403,88 @@ SHA1-Digest: 820CmLC9fE1O0AAZaeKrzW0ER0g=
 
 Name: modules/autoHide.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: T9SAawe0+UOMjMQizNLHDA==
-SHA1-Digest: 8KQ0JqLSzHH1tOjz/1jwh62zwxk=
+MD5-Digest: B9zP89rDOYvQbfDt8Zzygg==
+SHA1-Digest: fEWPNjGv/wd+jegY4ae6NViute0=
 
 Name: modules/base.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: q+mYhiRSG/v4AAbkIT4uCQ==
-SHA1-Digest: s804P4dgT5r0jnMU7tBb1JY85p8=
+MD5-Digest: SW7n5j5ulYqgVbALxDNHwg==
+SHA1-Digest: gshjveyfvCzlEasH+SJAVmhpduw=
 
 Name: modules/browser.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 992iLJmymDwfBlCenFMYxw==
-SHA1-Digest: HNf1gNRzLl9m9aWjpv6BUf8sOFk=
+MD5-Digest: Qsm9orLKQiwwI3wFGdgR5w==
+SHA1-Digest: lFCgOlN5J5AkJiLLgtWlAJLKKdI=
 
 Name: modules/browserUIShowHideObserver.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 8MSAEZpP7EhsHmIXnjzG7g==
-SHA1-Digest: M3SCb58qeNORSPot1UHe63vyftM=
+MD5-Digest: 1jGa2nmHU/8r438jcy8bxA==
+SHA1-Digest: 0ye5nfvkIj6pI35yGQAEL7xtJ+k=
 
 Name: modules/constants.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 6mbfJ7B8IX8ScrJgjSBh4g==
-SHA1-Digest: LekJDB7P9PtP/J5a+8+FANZtikM=
+MD5-Digest: bXcNFYoNHgH7Ut8DERrw9w==
+SHA1-Digest: YJ98EXt4ZUC8A9NCHjbj3fOUF6M=
 
 Name: modules/contentBridge.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: AZB2jQAnxsjypV1umhfEBw==
-SHA1-Digest: HFsqlRnRFb+hIdV7G5+MG3R0QUI=
+MD5-Digest: 8EkTrdJ8nAxYO+81/mRYig==
+SHA1-Digest: PjTvEP1WjiDk/FgiOz5XVHKr/+E=
 
 Name: modules/fullscreenObserver.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: mf/V54u6CtD6V2RFW/WF0Q==
-SHA1-Digest: v6+507G5urrawGK8lQh8JRdrcPo=
+MD5-Digest: dA4uF/PyD4eIAjQaZ1RIIQ==
+SHA1-Digest: ENKlU1ETpeEMx47y4xvTsSltvtw=
 
 Name: modules/fullTooltip.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: ShAuksj5Si0Sb0kEe1NwrQ==
-SHA1-Digest: 4DKc57PO/dO2V3oo0aNBOu7Dfkk=
+MD5-Digest: OTHa0q1gsOZFgz5uOQOE0Q==
+SHA1-Digest: SAU4UbMLDt9SVI9lrj/dfSoXe4k=
 
 Name: modules/groupTab.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: GdIHZgj3aQMqHtvRhbjv1w==
-SHA1-Digest: LhC5EqN9up0tyG7mzsxUD6ZxxUA=
+MD5-Digest: NL5i97YRH+b+XpG22i8tIA==
+SHA1-Digest: qefrneMChMj4kmaCaq19QCg/BqM=
 
 Name: modules/pseudoTreeBuilder.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 4q0nQ4CIjqaKtkWM3aHsZQ==
-SHA1-Digest: FzFEKrsUgN3ctHxnapuDMhdRXUQ=
+MD5-Digest: KsauIXOH18MRG4mEplXZfw==
+SHA1-Digest: 7EaG3t5WJWOobr8LTS9nX/ulAoI=
+
+Name: modules/ReferenceCounter.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: /+GL3pEvh8yXhOLV1KTL0g==
+SHA1-Digest: KwYUQNA0W5ensPrOgCQeR2NRGm4=
 
 Name: modules/tabAttributesObserver.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: V2bHwKcnECwSU9tiBq6oMA==
-SHA1-Digest: s0dTBYAbHaHJl1qosnFeq09v3wE=
+MD5-Digest: ASIvZ3RBvp7ujNIxUhHjhA==
+SHA1-Digest: E3qycu7EJPrhOGIYeCcsiHlDq/A=
 
 Name: modules/tabbarDNDObserver.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: uFs6iCDzp8ZlGMTsVMHM0Q==
-SHA1-Digest: JK+000vzvtosIaUhtvOl+yE5d2Y=
+MD5-Digest: Af1MrXXUChYdrEcE83+ljA==
+SHA1-Digest: jzjPtaYbneiJQrIL86DEi8H0qCQ=
 
 Name: modules/tabpanelDNDObserver.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: D2vLeI9JjyTH0dxUd3YjWw==
-SHA1-Digest: Ev0jhVn62wkkjNSOO5QHtGKBWXU=
+MD5-Digest: viIk0SD+R9Tc1k0cMgf98g==
+SHA1-Digest: NGDF4zuUWe9dhiX73LMiqEKgBnk=
 
 Name: modules/themeManager.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: AtFiQr5iJ7aRAIpw3ISe2w==
-SHA1-Digest: qxskOiLU34Yfh6Gxp/2rBD06gIQ=
+MD5-Digest: LKIpjU4H0S4zStz+u9J2FQ==
+SHA1-Digest: QRODHmwaRkX+b/zrhPVckxz7kf4=
 
 Name: modules/utils.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: zZ/+U7Sd8RvruD0Mknpl8A==
-SHA1-Digest: sdflsWuengne5M5scHCKGQ2KIWE=
+MD5-Digest: Evsu0Jey/gxHQtysi3qW9w==
+SHA1-Digest: z+FPUT6tjjGfA52pyzkH0LPYwB0=
 
 Name: modules/window.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: wxooRnHV0nCp3Bn7DQbN8g==
-SHA1-Digest: CiPCoI2sXL0Yt2kswj/w45/MU38=
+MD5-Digest: wYWu/aoxc/N0JO1GpDROKg==
+SHA1-Digest: 1UMTBrQ27VOYeSz+Lzk2iDFJiuQ=
 
 Name: modules/lib/animationManager.js
 Digest-Algorithms: MD5 SHA1
@@ -498,8 +508,8 @@ SHA1-Digest: 3IbYcqoRV/tpDPKB+iE5Y9iCjCo=
 
 Name: modules/lib/inherit.jsm
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: SESkSedzqkncyLXHABiaog==
-SHA1-Digest: NqtEgb7S1xm1jXEOznskOfZk/Sk=
+MD5-Digest: 5KlF2H6R+m4TNbqEUCxnag==
+SHA1-Digest: YS9YH8+s/xXoCob9P2p2s2DUouQ=
 
 Name: modules/lib/namespace.jsm
 Digest-Algorithms: MD5 SHA1
@@ -573,8 +583,8 @@ SHA1-Digest: SkZhMKbeatV48RFx9AROoyuLalc=
 
 Name: skin/classic/treestyletab/Linux-base.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: qcqsCQR2mdKUIuZFf9EEgA==
-SHA1-Digest: aQmL/lqslBMfWjHLumKMmUERwjo=
+MD5-Digest: jObYHMsAFuzN/olmy/FK4g==
+SHA1-Digest: IwwSyHMrakvDNVtGXz/itt/OdCQ=
 
 Name: skin/classic/treestyletab/Linux-config.css
 Digest-Algorithms: MD5 SHA1
@@ -603,8 +613,8 @@ SHA1-Digest: /CcGFdIzQT8ebf8twW9s6P1rRRI=
 
 Name: skin/classic/treestyletab/ui-base.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 5G3HB6CjHahNZTUpbtJsOQ==
-SHA1-Digest: jipVd7r7T1LUwqdguo6WxjwTdkY=
+MD5-Digest: f7hWW6ka4HhJp2x4iDlIrw==
+SHA1-Digest: SBpgkKqiRMt63i0rHc+TUMJoo1o=
 
 Name: skin/classic/treestyletab/WINNT-base.css
 Digest-Algorithms: MD5 SHA1
@@ -788,8 +798,8 @@ SHA1-Digest: CTg4j0P/755VUethbwqkLbDrXcI=
 
 Name: skin/classic/treestyletab/square/tab-surface.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: py4qLMM7RcXH+RwIHJE/Xw==
-SHA1-Digest: Ei6AJVrIrnKAL/qew2jLvNgXjWw=
+MD5-Digest: 09Z32P8AYKbhVLtelLGY8A==
+SHA1-Digest: uJCYdd6cnRl0V0Vt+sFUFWmD4oE=
 
 Name: skin/classic/treestyletab/square/vertigo.css
 Digest-Algorithms: MD5 SHA1
diff --git a/META-INF/mozilla.rsa b/META-INF/mozilla.rsa
index 3602901..3f13926 100644
Binary files a/META-INF/mozilla.rsa and b/META-INF/mozilla.rsa differ
diff --git a/META-INF/mozilla.sf b/META-INF/mozilla.sf
index 77eea90..6f46475 100644
--- a/META-INF/mozilla.sf
+++ b/META-INF/mozilla.sf
@@ -1,4 +1,4 @@
 Signature-Version: 1.0
-MD5-Digest-Manifest: b7fHst3iS1XpUeOAFDG0UA==
-SHA1-Digest-Manifest: icaPq7Iu/pZ1EMF/GPzMkCbIWFc=
+MD5-Digest-Manifest: qqshu9SyS0COjRVzsZbRkw==
+SHA1-Digest-Manifest: /jRGtjTb2V8ydEzI2MuaANhRgMg=
 
diff --git a/content/treestyletab/bookmarksOverlay.js b/content/treestyletab/bookmarksOverlay.js
index 1270725..91e51d0 100644
--- a/content/treestyletab/bookmarksOverlay.js
+++ b/content/treestyletab/bookmarksOverlay.js
@@ -3,6 +3,7 @@ XPCOMUtils.defineLazyModuleGetter(this,
   'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js');
 
 (function() {
+let { ReferenceCounter } = Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js', {});
 let { inherit } = Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm', {});
 var TreeStyleTabBookmarksService = inherit(TreeStyleTabService, {
 
@@ -218,13 +219,17 @@ var TreeStyleTabBookmarksService = inherit(TreeStyleTabService, {
 	preInit : function TSTBMService_preInit()
 	{
 		window.addEventListener('load', this, false);
+		ReferenceCounter.add('window,load,TSTBMService,false');
 		window.addEventListener(window['piro.sakura.ne.jp'].tabsDragUtils.EVENT_TYPE_TABS_DROP, this, false);
+		ReferenceCounter.add('window,EVENT_TYPE_TABS_DROP,TSTBMService,false');
 	},
 
 	init : function TSTBMService_init()
 	{
 		window.removeEventListener('load', this, false);
+		ReferenceCounter.remove('window,load,TSTBMService,false');
 		window.addEventListener('unload', this, false);
+		ReferenceCounter.add('window,unload,TSTBMService,false');
 
 		if (!('PlacesUIUtils' in window)) return;
 
@@ -473,7 +478,9 @@ var TreeStyleTabBookmarksService = inherit(TreeStyleTabService, {
 	destroy : function TSTBMService_destroy()
 	{
 		window.removeEventListener('unload', this, false);
+		ReferenceCounter.remove('window,unload,TSTBMService,false');
 		window.removeEventListener(window['piro.sakura.ne.jp'].tabsDragUtils.EVENT_TYPE_TABS_DROP, this, false);
+		ReferenceCounter.remove('window,EVENT_TYPE_TABS_DROP,TSTBMService,false');
 	},
 
 	// observer for nsINavBookmarksService 
diff --git a/content/treestyletab/bookmarksOverlayEditable.js b/content/treestyletab/bookmarksOverlayEditable.js
index 8bf57d7..c529c3f 100644
--- a/content/treestyletab/bookmarksOverlayEditable.js
+++ b/content/treestyletab/bookmarksOverlayEditable.js
@@ -3,6 +3,7 @@ XPCOMUtils.defineLazyModuleGetter(this,
   'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js');
 
 (function() {
+let { ReferenceCounter } = Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js', {});
 let { inherit } = Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm', {});
 var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService, {
 
@@ -386,6 +387,7 @@ var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService,
 		{
 			case 'DOMContentLoaded':
 				window.removeEventListener('DOMContentLoaded', this, false);
+				ReferenceCounter.remove('window,DOMContentLoaded,TreeStyleTabBookmarksServiceEditable,false');
 				this.init();
 				break;
 		}
@@ -394,6 +396,7 @@ var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService,
 });
 
 window.addEventListener('DOMContentLoaded', TreeStyleTabBookmarksServiceEditable, false);
+ReferenceCounter.add('window,DOMContentLoaded,TreeStyleTabBookmarksServiceEditable,false');
 
 window.TreeStyleTabBookmarksServiceEditable = TreeStyleTabBookmarksServiceEditable;
 })();
diff --git a/content/treestyletab/content-utils.js b/content/treestyletab/content-utils.js
new file mode 100644
index 0000000..511af1d
--- /dev/null
+++ b/content/treestyletab/content-utils.js
@@ -0,0 +1,55 @@
+(function(global) {
+	var DEBUG = false;
+	function mydump(aMessage) {
+		if (DEBUG)
+			dump('treestyletab(general) content utils: '+aMessage +'\n');
+	}
+	mydump('CONTENT SCRIPT LOADED <'+global.content.location+'>');
+
+	var Cc = Components.classes;
+	var Ci = Components.interfaces;
+	var Cu = Components.utils;
+	var Cr = Components.results;
+
+	var { TreeStyleTabConstants } = Cu.import('resource://treestyletab-modules/constants.js', {});
+
+	function free() {
+		cleanup =
+			Cc = Ci = Cu = Cr =
+			TreeStyleTabConstants =
+			messageListener =
+			handleEvent =
+			mydump =
+				undefined;
+	}
+
+	var messageListener = function(aMessage) {
+		mydump('CONTENT MESSAGE LISTENED <'+(global.content && global.content.location)+'>');
+		mydump(JSON.stringify(aMessage.json));
+		switch (aMessage.json.command)
+		{
+			case TreeStyleTabConstants.COMMAND_SHUTDOWN:
+				global.removeMessageListener(TreeStyleTabConstants.MESSAGE_TYPE, messageListener);
+				global.removeEventListener('selectionchange', handleEvent, true);
+				free();
+				return;
+		}
+	};
+	global.addMessageListener(TreeStyleTabConstants.MESSAGE_TYPE, messageListener);
+
+	function handleEvent(aEvent) {
+		switch (aEvent.type)
+		{
+			case 'selectionchange':
+				if (!aEvent.target ||
+					!aEvent.target.getSelection)
+					return;
+				global.sendAsyncMessage(TreeStyleTabConstants.MESSAGE_TYPE, {
+					command : TreeStyleTabConstants.COMMAND_REPORT_SELECTION_CHANGE,
+					text    : aEvent.target.getSelection().toString()
+				});
+				return;
+		}
+	}
+	global.addEventListener('selectionchange', handleEvent, true);
+})(this);
diff --git a/content/treestyletab/res/bookmarkMultipleTabs.xul b/content/treestyletab/res/bookmarkMultipleTabs.xul
index d282cf0..775791a 100644
--- a/content/treestyletab/res/bookmarkMultipleTabs.xul
+++ b/content/treestyletab/res/bookmarkMultipleTabs.xul
@@ -14,7 +14,7 @@
    in JS files:
      window['piro.sakura.ne.jp'].bookmarkMultipleTabs.addBookmarkFor(tabsArray, folderName);
 
- license: The MIT License, Copyright (c) 2009-2012 YUKI "Piro" Hiroshi
+ license: The MIT License, Copyright (c) 2009-2015 YUKI "Piro" Hiroshi
  original:
    http://github.com/piroor/fxaddonlib-bookmark-multiple-tabs
 -->
@@ -24,7 +24,7 @@
 window.addEventListener('DOMContentLoaded', function() {
 	window.removeEventListener('DOMContentLoaded', arguments.callee, true);
 
-	const currentRevision = 5;
+	const currentRevision = 8;
 
 	if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {};
 
@@ -72,9 +72,6 @@ window.addEventListener('DOMContentLoaded', function() {
 							hiddenRows : ['description', 'location', 'loadInSidebar', 'keyword']
 						}, window);
 					}
-					else if ('showMinimalAddMultiBookmarkUI' in utils) { // Firefox 3 - 8
-						utils.showMinimalAddMultiBookmarkUI(tabs);
-					}
 					else {
 						throw new Error('there is no method to create bookmarks from tabs!');
 					}
diff --git a/content/treestyletab/res/bookmarkMultipleTabs_bookmarkPropertiesOverlay.xul b/content/treestyletab/res/bookmarkMultipleTabs_bookmarkPropertiesOverlay.xul
index beb26b6..23e0488 100644
--- a/content/treestyletab/res/bookmarkMultipleTabs_bookmarkPropertiesOverlay.xul
+++ b/content/treestyletab/res/bookmarkMultipleTabs_bookmarkPropertiesOverlay.xul
@@ -14,7 +14,7 @@
    in JS files:
      window['piro.sakura.ne.jp'].bookmarkMultipleTabs.addBookmarkFor(tabsArray, folderName);
 
- license: The MIT License, Copyright (c) 2009-2012 YUKI "Piro" Hiroshi
+ license: The MIT License, Copyright (c) 2009-2015 YUKI "Piro" Hiroshi
    http://github.com/piroor/fxaddonlibs/blob/master/license.txt
  original:
    http://github.com/piroor/fxaddonlibs/blob/master/bookmarkMultipleTabs.xul
@@ -28,23 +28,32 @@
 		BookmarkPropertiesPanel._determineItemInfo.toSource().indexOf('__folderNameOverride') > -1)
 		return;
 
-	eval('BookmarkPropertiesPanel._determineItemInfo = '+BookmarkPropertiesPanel._determineItemInfo.toSource().replace(
-		'{',
-		['{',
-			'var __folderNameOverride = null;',
-			'try {',
-			'	__folderNameOverride = Components.classes["@mozilla.org/preferences;1"]',
-			'		.getService(Components.interfaces.nsIPrefBranch)',
-			'		.getCharPref("temp.showMinimalAddMultiBookmarkUI.folderName");',
-			'	__folderNameOverride = decodeURIComponent(escape(__folderNameOverride));',
-			'}',
-			'catch(e) {',
-			'}'
-		].join('')
-	).replace(
-		'this._strings.getString("bookmarkAllTabsDefault")',
-		'__folderNameOverride || $&'
-	));
+	// Defined at http://mxr.mozilla.org/mozilla-central/source/browser/components/places/content/bookmarkProperties.js#73
+	const ACTION_ADD = 1;
+
+	BookmarkPropertiesPanel.__treestyletab__determineItemInfo = BookmarkPropertiesPanel._determineItemInfo;
+	BookmarkPropertiesPanel._determineItemInfo = function(...aArgs) {
+		var folderNameOverride = null;
+		try {
+			folderNameOverride = Components.classes['@mozilla.org/preferences;1']
+				.getService(Components.interfaces.nsIPrefBranch)
+				.getCharPref('temp.showMinimalAddMultiBookmarkUI.folderName');
+			folderNameOverride = decodeURIComponent(escape(folderNameOverride));
+		}
+		catch(e) {
+		}
+		var retVal = this.__treestyletab__determineItemInfo.apply(this, aArgs);
+		if (folderNameOverride &&
+			this._action == ACTION_ADD) {
+			let dialogInfo = window.arguments[0];
+			if (dialogInfo.type === 'folder' &&
+				!('title' in dialogInfo) &&
+				'URIList' in dialogInfo) {
+				this._title = folderNameOverride;
+			}
+		}
+		return retVal;
+	};
 })();
 ]]></script>
 </overlay>
diff --git a/content/treestyletab/res/tabsDragUtils.js b/content/treestyletab/res/tabsDragUtils.js
index 7debcdd..a3ea13d 100644
--- a/content/treestyletab/res/tabsDragUtils.js
+++ b/content/treestyletab/res/tabsDragUtils.js
@@ -15,7 +15,7 @@
    http://github.com/piroor/fxaddonlib-tabs-drag-utils
 */
 (function() {
-	const currentRevision = 33;
+	const currentRevision = 35;
 
 	if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {};
 
@@ -54,12 +54,12 @@
 		getRestoringData: function(aTab)
 		{
 			var data = aTab.linkedBrowser.__SS_data;
-			if (!data && this.RestoringTabsData) // Firefox 23-
-				data = this.RestoringTabsData.get(aTab.linkedBrowser);
+			if (!data && this.TabStateCache) // Firefox 23-
+				data = this.TabStateCache.get(aTab.linkedBrowser);
 			return data;
 		},
-		get TabRestoreStates() {
-			return this.SessionStoreNS.TabRestoreStates;
+		get TabStateCache() {
+			return this.SessionStoreNS.TabStateCache;
 		},
 		get SessionStoreNS() {
 			delete this.SessionStoreNS;
@@ -159,17 +159,32 @@
 		{
 			this.updatedTabDNDObservers.push(aObserver);
 
-			if ('_setEffectAllowedForDataTransfer' in aObserver &&
-				aObserver._setEffectAllowedForDataTransfer.toSource().indexOf('tabsDragUtils') < 0) {
-				let original = aObserver._setEffectAllowedForDataTransfer;
-				aObserver.__TabsDragUtils_original__setEffectAllowedForDataTransfer = original;
-				eval('aObserver._setEffectAllowedForDataTransfer = '+
-					original.toSource().replace(
-						'dt.mozItemCount > 1',
-						'$& && !window["piro.sakura.ne.jp"].tabsDragUtils.isTabsDragging(arguments[0])'
-					)
-				);
-				aObserver.__TabsDragUtils_updated__setEffectAllowedForDataTransfer = aObserver._setEffectAllowedForDataTransfer;
+			if (typeof aObserver._setEffectAllowedForDataTransfer === 'function') { // Firefox 43 and older
+				if (aObserver._setEffectAllowedForDataTransfer.toSource().indexOf('tabsDragUtils') < 0) {
+					let original = aObserver._setEffectAllowedForDataTransfer;
+					aObserver.__TabsDragUtils_original__setEffectAllowedForDataTransfer = original;
+					eval('aObserver._setEffectAllowedForDataTransfer = '+
+						original.toSource().replace(
+							'dt.mozItemCount > 1',
+							'$& && !window["piro.sakura.ne.jp"].tabsDragUtils.isTabsDragging(arguments[0])'
+						)
+					);
+					aObserver.__TabsDragUtils_updated__setEffectAllowedForDataTransfer = aObserver._setEffectAllowedForDataTransfer;
+				}
+			}
+			else { // Firefox 44 and later
+				if (typeof aObserver._getDropEffectForTabDrag === 'function' &&
+					aObserver._getDropEffectForTabDrag.toSource().indexOf('tabsDragUtils') < 0) {
+					let original = aObserver._getDropEffectForTabDrag;
+					aObserver.__TabsDragUtils_original__getDropEffectForTabDrag = original;
+					eval('aObserver._getDropEffectForTabDrag = '+
+						original.toSource().replace(
+							'dt.mozItemCount > 1',
+							'$& && !window["piro.sakura.ne.jp"].tabsDragUtils.isTabsDragging(arguments[0])'
+						)
+					);
+					aObserver.__TabsDragUtils_updated__getDropEffectForTabDrag = aObserver._getDropEffectForTabDrag;
+				}
 			}
 
 			if ('_animateTabMove' in aObserver &&
@@ -573,6 +588,11 @@
 			if (!aObserver)
 				return;
 
+			if (aObserver._getDropEffectForTabDrag == aObserver.__TabsDragUtils_updated__getDropEffectForTabDrag)
+				aObserver._getDropEffectForTabDrag = aObserver.__TabsDragUtils_original__getDropEffectForTabDrag;
+			delete aObserver.__TabsDragUtils_original__getDropEffectForTabDrag;
+			delete aObserver.__TabsDragUtils_updated__getDropEffectForTabDrag;
+
 			if (aObserver._setEffectAllowedForDataTransfer == aObserver.__TabsDragUtils_updated__setEffectAllowedForDataTransfer)
 				aObserver._setEffectAllowedForDataTransfer = aObserver.__TabsDragUtils_original__setEffectAllowedForDataTransfer;
 			delete aObserver.__TabsDragUtils_original__setEffectAllowedForDataTransfer;
@@ -839,7 +859,8 @@
 		{
 			if (this.isTabNeedToBeRestored(aTab)) {
 				let data = this.getRestoringData(aTab);
-				let entry = data.entries[Math.min(data.index, data.entries.length-1)];
+				let history = data.history;
+				let entry = history.entries[Math.min(history.index, history.entries.length-1)];
 				if (entry) return entry.url;
 			}
 			return aTab.linkedBrowser.currentURI.spec;
diff --git a/content/treestyletab/treestyletab.css b/content/treestyletab/treestyletab.css
index dc353f0..81c14f5 100644
--- a/content/treestyletab/treestyletab.css
+++ b/content/treestyletab/treestyletab.css
@@ -77,16 +77,25 @@
 
 /* tab bar in the DOM-fullscreen mode */
 
-.tabbrowser-tabs[treestyletab-dom-fullscreen-activated="true"],
-.tabbrowser-strip[treestyletab-dom-fullscreen-activated="true"],
-.tabbrowser-strip[treestyletab-dom-fullscreen-activated="true"]+splitter,
-.treestyletab-tabbar-toolbar[treestyletab-dom-fullscreen-activated="true"],
-.treestyletab-tabbar-toolbar[treestyletab-dom-fullscreen-activated="true"] > *,
-tabbrowser[treestyletab-dom-fullscreen-activated-mode="true"][tabcontainer]
+:root[inDOMFullscreen="true"]
+  .tabbrowser-tabs,
+:root[inDOMFullscreen="true"]
+  .tabbrowser-strip,
+:root[inDOMFullscreen="true"]
+  .tabbrowser-strip+splitter,
+:root[inDOMFullscreen="true"]
+  .treestyletab-tabbar-toolbar,
+:root[inDOMFullscreen="true"]
+  .treestyletab-tabbar-toolbar > *,
+:root[inDOMFullscreen="true"]
+  tabbrowser[tabcontainer]
   .tabbrowser-strip.treestyletab-tabbar-placeholder,
-tabbrowser[treestyletab-dom-fullscreen-activated-mode="true"][tabcontainer]
-  .tabbrowser-strip.treestyletab-tabbar-placeholder+splitter {
-	visibility: collapse;
+:root[inDOMFullscreen="true"]
+  tabbrowser[tabcontainer]
+  .tabbrowser-strip.treestyletab-tabbar-placeholder+splitter,
+:root[inDOMFullscreen="true"]
+  .treestyletab-tabbar-toggler {
+	visibility: collapse !important;
 }
 
 
@@ -282,7 +291,7 @@ tabs.tabbrowser-tabs[treestyletab-tabbar-position="left"][treestyletab-invert-sc
  * Normal selectors in default theme is stronger than :-moz-any() even if
  * it includes #TabsToolbar in its subqueries.
  */
- at media all and (-moz-windows-compositor) { /* for winstripe */
+ at media all and (-moz-windows-compositor) { /* for winstripe: Windows */
 	#navigator-toolbox
 	  > .treestyletab-tabbar-toolbar:not(#toolbar-menubar),
 	#navigator-toolbox
@@ -378,12 +387,12 @@ tabs.tabbrowser-tabs[treestyletab-tabbar-position="left"][treestyletab-invert-sc
 }
 .treestyletab-tabbar-toolbar,
 .treestyletab-tabbar-toolbar-ready,
-/* for gnomestripe */
+/* for gnomestripe: Linux */
 #TabsToolbar.treestyletab-tabbar-toolbar:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
 #TabsToolbar.treestyletab-tabbar-toolbar:not([autohide="true"])[tabsontop="true"]:not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
 #TabsToolbar.treestyletab-tabbar-toolbar-ready:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
 #TabsToolbar.treestyletab-tabbar-toolbar-ready:not([autohide="true"])[tabsontop="true"]:not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
-/* for pinstripe */
+/* for pinstripe: OS X */
 toolbar.treestyletab-tabbar-toolbar:not([nowindowdrag="true"]),
 toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
 /* Hide Caption Titlebar Plus (Smart)
@@ -595,9 +604,17 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
 	/* width: 24px; */
 	z-index: 100;
 }
+*[collapsed="true"]
+  .tabbrowser-tabs[treestyletab-mode="vertical"]
+  .tabbrowser-tab[pinned],
+*[collapsed="true"]
+  .tabbrowser-tabs[treestyletab-mode="vertical"]
+  .tabbrowser-tab[pinned] * /* this is required to hide unexpectedly shown gray rect (ex. .tab-background) */,
 .tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-dom-fullscreen-activated="true"]
-  .tabbrowser-tab[pinned] {
-	z-index: -100;
+  .tabbrowser-tab[pinned],
+.tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-dom-fullscreen-activated="true"]
+  .tabbrowser-tab[pinned] * /* this is required to hide unexpectedly shown gray rect (ex. .tab-background) */ {
+	visibility: collapse;
 }
 
 .tabbrowser-tabs[treestyletab-mode="vertical"]
diff --git a/content/treestyletab/treestyletab.js b/content/treestyletab/treestyletab.js
index cd47d71..4b63e06 100644
--- a/content/treestyletab/treestyletab.js
+++ b/content/treestyletab/treestyletab.js
@@ -1,21 +1,27 @@
 (function() {
+	let { ReferenceCounter } = Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js', {});
 	/**
 	 * On secondary (and later) window, SSWindowStateBusy event can be fired
 	 * before DOMContentLoaded, on "domwindowopened".
 	 */
 	var SSWindowStateBusyListener = function TSTSSWindowStateBusyListener(aEvent) {
 			window.removeEventListener(aEvent.type, TSTSSWindowStateBusyListener, false);
+			ReferenceCounter.remove('window,aEvent.type,TSTSSWindowStateBusyListener,false');
 			window.__treestyletab__WindowStateBusy = true;
 			SSWindowStateBusyListener = undefined;
 		};
 	window.addEventListener('SSWindowStateBusy', SSWindowStateBusyListener, false);
+	ReferenceCounter.add('window,SSWindowStateBusy,SSWindowStateBusyListener,false');
 	window.addEventListener('DOMContentLoaded', function onDOMContentLoaded(aEvent) {
 		window.removeEventListener(aEvent.type, onDOMContentLoaded, false);
+		ReferenceCounter.remove('window,aEvent.type,onDOMContentLoaded,false');
 		if (SSWindowStateBusyListener) {
 			window.removeEventListener('SSWindowStateBusy', SSWindowStateBusyListener, false);
+			ReferenceCounter.remove('window,SSWindowStateBusy,SSWindowStateBusyListener,false');
 			SSWindowStateBusyListener = undefined;
 		}
 	}, false);
+	ReferenceCounter.add('window,aEvent.type,onDOMContentLoaded,false');
 
 	var ns = {};
 	Components.utils.import('resource://treestyletab-modules/window.js', ns);
diff --git a/content/treestyletab/windowHelper.js b/content/treestyletab/windowHelper.js
index 9ece3be..0537e3b 100644
--- a/content/treestyletab/windowHelper.js
+++ b/content/treestyletab/windowHelper.js
@@ -3,6 +3,7 @@ XPCOMUtils.defineLazyModuleGetter(this,
   'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js');
 
 var TreeStyleTabWindowHelper = { 
+	runningDelayedStartup : false,
 	
 	get service() 
 	{
@@ -11,43 +12,35 @@ var TreeStyleTabWindowHelper = {
  
 	preInit : function TSTWH_preInit() 
 	{
-		TreeStyleTabUtils.doPatching(gBrowserInit._delayedStartup, 'gBrowserInit._delayedStartup', function(aName, aSource) {
-			if (aSource.indexOf('!MultipleTabService.tearOffSelectedTabsFromRemote()') > -1) {
-				return eval(aName+' = '+aSource.replace(
-					'!MultipleTabService.tearOffSelectedTabsFromRemote()',
-					'!TreeStyleTabService.tearOffSubtreeFromRemote() && $&'
-				));
-			}
-			else if (aSource.indexOf('gBrowser.swapBrowsersAndCloseOther') > -1) {
-				return eval(aName+' = '+aSource.replace(
-					/gBrowser\.swapBrowsersAndCloseOther\([^)]+\);/g,
-					'if (!TreeStyleTabService.tearOffSubtreeFromRemote()) { $& }'
-				).replace(
-					// Workaround for https://github.com/piroor/treestyletab/issues/741
-					// After the function is updated by TST, reassignment of a global variable raises an error like:
-					// > System JS : ERROR chrome://treestyletab/content/windowHelper.js line 30 > eval:130 - TypeError: can't redefine non-configurable property 'gBidiUI'
-					// If I access it as a property of the global object, the error doesn't appear.
-					/([^\.])\bgBidiUI =/,
-					'$1window.gBidiUI ='
-				));
+		gBrowserInit.__treestyletab___delayedStartup = gBrowserInit._delayedStartup;
+		gBrowserInit._delayedStartup = function(...args) {
+			TreeStyleTabWindowHelper.runningDelayedStartup = true;
+			var retVal = this.__treestyletab___delayedStartup.apply(this, args);
+			TreeStyleTabWindowHelper.runningDelayedStartup = false;
+			return retVal;
+		};
+
+		nsBrowserAccess.prototype.__treestyletab__openURI = nsBrowserAccess.prototype.openURI;
+		nsBrowserAccess.prototype.openURI = function(aURI, aOpener, aWhere, aContext) {
+			var where = aWhere;
+			if (where === Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW) {
+				let isExternal = aContext === Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL;
+				let overridePref = TreeStyleTabUtils.prefs.getPref('browser.link.open_newwindow.override.external');
+				if (isExternal && overridePref !== null)
+					where = overridePref;
+				else
+					where = TreeStyleTabUtils.prefs.getPref('browser.link.open_newwindow');
 			}
-		}, 'TreeStyleTab');
-
-		TreeStyleTabUtils.doPatching(nsBrowserAccess.prototype.openURI, 'nsBrowserAccess.prototype.openURI', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				/(switch\s*\(aWhere\))/,
-				'TreeStyleTabService.onBeforeBrowserAccessOpenURI(aOpener, aWhere, aContext); $1'
-			));
-		}, 'TreeStyleTab');
+			TreeStyleTabService.onBeforeBrowserAccessOpenURI(aOpener, where, aContext);
+			return this.__treestyletab__openURI.call(this, aURI, aOpener, aWhere, aContext);
+		};
 
-		TreeStyleTabUtils.doPatching(nsBrowserAccess.prototype.openURIInFrame, 'nsBrowserAccess.prototype.openURIInFrame', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'let browser = ',
-				// Use "arguments[1]" instead of "aOwner" or "aParams".
-				// The argument name is changed from "aOwner" to "aParams" by https://bugzilla.mozilla.org/show_bug.cgi?id=1058116
-				'TreeStyleTabService.onBeforeBrowserAccessOpenURI(arguments[1], aWhere, aContext); $&'
-			));
-		}, 'TreeStyleTab');
+		nsBrowserAccess.prototype.__treestyletab__openURIInFrame = nsBrowserAccess.prototype.openURIInFrame;
+		nsBrowserAccess.prototype.openURIInFrame = function(aURI, aParams, aWhere, aContext) {
+			if (aWhere === Ci.nsIBrowserDOMWindow.OPEN_NEWTAB)
+				TreeStyleTabService.onBeforeBrowserAccessOpenURI(aParams, aWhere, aContext);
+			return this.__treestyletab__openURIInFrame.call(this, aURI, aParams, aWhere, aContext);
+		};
 
 		if ('TabsInTitlebar' in window) {
 			TreeStyleTabUtils.doPatching(TabsInTitlebar._update, 'TabsInTitlebar._update', function(aName, aSource) {
@@ -58,29 +51,23 @@ var TreeStyleTabWindowHelper = {
 			}, 'treeStyleTab');
 		}
 
-		TreeStyleTabUtils.doPatching(window.BrowserOpenTab, 'window.BrowserOpenTab', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'openUILinkIn(',
-				'gBrowser.treeStyleTab.onBeforeNewTabCommand(); $&'
-			));
-		}, 'treeStyleTab');
-
-		TreeStyleTabUtils.doPatching(window.undoCloseTab, 'window.undoCloseTab', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				/(\btab\s*=\s*[^\.]+\.undoCloseTab\([^;]+\);)/,
-				'gBrowser.__treestyletab__doingUndoCloseTab = true;\n' +
-				'$1\n' +
-				'tab.__treestyletab__restoredByUndoCloseTab = true;\n' +
-				'setTimeout(function() { delete gBrowser.__treestyletab__doingUndoCloseTab; }, 0);'
-			));
-		}, 'treestyletab');
-
-		TreeStyleTabUtils.doPatching(window.XULBrowserWindow.hideChromeForLocation, 'XULBrowserWindow.hideChromeForLocation', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'{',
-				'{ if (gBrowser.treeStyleTab.isVertical) return false;\n'
-			));
-		}, 'treeStyleTab');
+		window.__treestyletab__BrowserOpenTab = window.BrowserOpenTab;
+		window.BrowserOpenTab = function(...aArgs) {
+			gBrowser.treeStyleTab.onBeforeNewTabCommand();
+			return this.__treestyletab__BrowserOpenTab.apply(this, aArgs);
+		};
+
+		window.__treestyletab__undoCloseTab = window.undoCloseTab;
+		window.undoCloseTab = function(...aArgs) {
+			gBrowser.__treestyletab__doingUndoCloseTab = true;
+			var tab = this.__treestyletab__undoCloseTab.apply(this, aArgs);
+			if (tab)
+				tab.__treestyletab__restoredByUndoCloseTab = true;
+			setTimeout(function() {
+				delete gBrowser.__treestyletab__doingUndoCloseTab;
+			}, 0);
+			return tab;
+		};
 
 		[
 			'window.duplicateTab.handleLinkClick',
@@ -109,6 +96,19 @@ var TreeStyleTabWindowHelper = {
 	{
 		this.overrideExtensionsBeforeBrowserInit(); // windowHelperHacks.js
 		this.overrideGlobalFunctions();
+
+		// Replacing of gBrowserInit._delayedStartup() with eval()
+		// breaks the variable scope of the function and break its
+		// functionality completely.
+		// Instead, I change the behavior of the method only at the
+		// startup process.
+		gBrowser.__treestyletab__swapBrowsersAndCloseOther = gBrowser.swapBrowsersAndCloseOther;
+		gBrowser.swapBrowsersAndCloseOther = function(...args) {
+			if (TreeStyleTabWindowHelper.runningDelayedStartup &&
+				TreeStyleTabService.tearOffSubtreeFromRemote())
+				return;
+			return this.__treestyletab__swapBrowsersAndCloseOther.apply(this, args);
+		};
 	},
  
 	onAfterBrowserInit : function TSTWH_onAfterBrowserInit() 
@@ -127,93 +127,121 @@ var TreeStyleTabWindowHelper = {
 			)
 			aObserver = aObserver.tabContainer;
 
-		TreeStyleTabUtils.doPatching(aObserver._setEffectAllowedForDataTransfer, aObserver+'._setEffectAllowedForDataTransfer', function(aName, aSource) {
-			return eval('aObserver._setEffectAllowedForDataTransfer = '+aSource.replace(
-				'{',
-				'{ var TSTTabBrowser = this instanceof Element ? (this.tabbrowser || this) : gBrowser ; var TST = TSTTabBrowser.treeStyleTab;'
-			).replace(
-				/\.screenX/g, '[TST.screenPositionProp]'
-			).replace(
-				/\.width/g, '[TST.sizeProp]'
-			).replace(
-				/(return (?:true|dt.effectAllowed = "copyMove");)/,
-				'if (!TST.tabbarDNDObserver.canDropTab(arguments[0])) {\n' +
-				'  return dt.effectAllowed = "none";\n' +
-				'}\n' +
-				'$1'
-			).replace(
-				'sourceNode.parentNode == this &&',
-				'$& TST.getTabFromEvent(event) == sourceNode &&'
-			));
-		}, 'TST');
+		if (typeof aObserver._setEffectAllowedForDataTransfer === 'function') { // Firefox 43 and older
+			TreeStyleTabUtils.doPatching(aObserver._setEffectAllowedForDataTransfer, aObserver+'._setEffectAllowedForDataTransfer', function(aName, aSource) {
+				return eval('aObserver._setEffectAllowedForDataTransfer = '+aSource.replace(
+					'{',
+					'{ var TSTTabBrowser = this instanceof Element ? (this.tabbrowser || this) : gBrowser ; var TST = TSTTabBrowser.treeStyleTab;'
+				).replace(
+					/\.screenX/g, '[TST.screenPositionProp]'
+				).replace(
+					/\.width/g, '[TST.sizeProp]'
+				).replace(
+					/(return (?:true|dt.effectAllowed = "copyMove");)/,
+					'if (!TST.tabbarDNDObserver.canDropTab(arguments[0])) {\n' +
+					'  return dt.effectAllowed = "none";\n' +
+					'}\n' +
+					'$1'
+				).replace(
+					'sourceNode.parentNode == this &&',
+					'$& TST.getTabFromEvent(event) == sourceNode &&'
+				));
+			}, 'TST');
+		}
+		else { // Firefox 44 and later
+			aObserver.__treestyletab__getDropEffectForTabDrag = aObserver._getDropEffectForTabDrag;
+			aObserver._getDropEffectForTabDrag = function(...aArgs) {
+				var effects = this.__treestyletab__getDropEffectForTabDrag.apply(this, aArgs);
+				if (effects === 'copy' || effects === 'move') {
+					let TSTTabBrowser = this instanceof Element ? (this.tabbrowser || this) : gBrowser ;
+					var TST = TSTTabBrowser.treeStyleTab
+					if (!TST.tabbarDNDObserver.canDropTab(aArgs[0]))
+						effects = 'none';
+				}
+				return effects;
+			};
+		}
 	},
  
 	overrideGlobalFunctions : function TSTWH_overrideGlobalFunctions() 
 	{
 		this.initToolbarItems();
 
-		TreeStyleTabUtils.doPatching(nsContextMenu.prototype.openLinkInTab, 'nsContextMenu.prototype.openLinkInTab', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'{',
-				'{\n' +
-				'  TreeStyleTabService.handleNewTabFromCurrent(this.target.ownerDocument.defaultView);'
-			));
-		}, 'TreeStyleTab');
-
-		TreeStyleTabUtils.doPatching(nsContextMenu.prototype.openFrameInTab, 'nsContextMenu.prototype.openFrameInTab', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'{',
-				'{\n' +
-				'  TreeStyleTabService.handleNewTabFromCurrent(this.target.ownerDocument.defaultView);'
-			));
-		}, 'TreeStyleTab');
-
-		var viewImageMethod = ('viewImage' in nsContextMenu.prototype) ? 'viewImage' : 'viewMedia' ;
-		TreeStyleTabUtils.doPatching(nsContextMenu.prototype[viewImageMethod], 'nsContextMenu.prototype.'+viewImageMethod, function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				/(openUILink\()/g,
-				'TreeStyleTabService.onBeforeViewMedia(e, this.target.ownerDocument.defaultView); $1'
-			));
-		}, 'TreeStyleTab');
-
-		TreeStyleTabUtils.doPatching(nsContextMenu.prototype.viewBGImage, 'nsContextMenu.prototype.viewBGImage', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'openUILink(',
-				'TreeStyleTabService.onBeforeViewMedia(e, this.target.ownerDocument.defaultView); $&'
-			));
-		}, 'TreeStyleTab');
-
-		TreeStyleTabUtils.doPatching(nsContextMenu.prototype.addDictionaries, 'nsContextMenu.prototype.addDictionaries', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'openUILinkIn(',
-				'TreeStyleTabService.onBeforeOpenLink(where, this.target.ownerDocument.defaultView); $&'
-			));
-		}, 'TreeStyleTab');
-
-		TreeStyleTabUtils.doPatching(BrowserSearch._loadSearch, 'BrowserSearch._loadSearch', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'openLinkIn(',
-				'TreeStyleTabService.onBeforeBrowserSearch(arguments[0], useNewTab); $&'
-			));
-		}, 'TreeStyleTab');
-
-		TreeStyleTabUtils.doPatching(window.openLinkIn, 'window.openLinkIn', function(aName, aSource) {
-			// Bug 1050447 changed this line in Fx 34 to
-			// newTab = w.gBrowser.loadOneTab(
-			// Bug 1108555 removed newTab assignment
-			return eval(aName+' = '+aSource.replace(
-				/((b|(newTab = )?w\.gB)rowser.loadOneTab\()/g,
-				'TreeStyleTabService.onBeforeOpenLinkWithTab(gBrowser.selectedTab, aFromChrome); $1'
-			));
-		}, 'TreeStyleTab');
+		nsContextMenu.prototype.__treestyletab__openLinkInTab = nsContextMenu.prototype.openLinkInTab;
+		nsContextMenu.prototype.openLinkInTab = function(...aArgs) {
+			TreeStyleTabService.handleNewTabFromCurrent(this.target.ownerDocument.defaultView);
+			return this.__treestyletab__openLinkInTab.apply(this, aArgs);
+		};
+
+		nsContextMenu.prototype.__treestyletab__openFrameInTab = nsContextMenu.prototype.openFrameInTab;
+		nsContextMenu.prototype.openFrameInTab = function(...aArgs) {
+			TreeStyleTabService.handleNewTabFromCurrent(this.target.ownerDocument.defaultView);
+			return this.__treestyletab__openFrameInTab.apply(this, aArgs);
+		};
+
+		nsContextMenu.prototype.__treestyletab__viewMedia = nsContextMenu.prototype.viewMedia;
+		nsContextMenu.prototype.viewMedia = function(aEvent) {
+			TreeStyleTabService.onBeforeViewMedia(aEvent, this.target.ownerDocument.defaultView);
+			return this.__treestyletab__viewMedia.call(this, aEvent);
+		};
+
+		nsContextMenu.prototype.__treestyletab__viewBGImage = nsContextMenu.prototype.viewBGImage;
+		nsContextMenu.prototype.viewBGImage = function(aEvent) {
+			TreeStyleTabService.onBeforeViewMedia(aEvent, this.target.ownerDocument.defaultView);
+			return this.__treestyletab__viewBGImage.call(this, aEvent);
+		};
+
+		nsContextMenu.prototype.__treestyletab__addDictionaries = nsContextMenu.prototype.addDictionaries;
+		nsContextMenu.prototype.addDictionaries = function(...aArgs) {
+			var newWindowPref = TreeStyleTabUtils.prefs.getPref('browser.link.open_newwindow');
+			var where = newWindowPref === 3 ? 'tab' : 'window' ;
+			TreeStyleTabService.onBeforeOpenLink(where, this.target.ownerDocument.defaultView);
+			return this.__treestyletab__addDictionaries.apply(this, aArgs);
+		};
+
+		nsContextMenu.prototype.__treestyletab__viewPartialSource = nsContextMenu.prototype.viewPartialSource;
+		nsContextMenu.prototype.viewPartialSource = function(...aArgs) {
+			TreeStyleTabService.handleNewTabFromCurrent(this.target.ownerDocument.defaultView);
+			return this.__treestyletab__viewPartialSource.apply(this, aArgs);
+		};
+
+		nsContextMenu.prototype.__treestyletab__viewFrameSource = nsContextMenu.prototype.viewFrameSource;
+		nsContextMenu.prototype.viewFrameSource = function(...aArgs) {
+			TreeStyleTabService.handleNewTabFromCurrent(this.target.ownerDocument.defaultView);
+			return this.__treestyletab__viewFrameSource.apply(this, aArgs);
+		};
+
+		window.__treestyletab__BrowserViewSource = window.BrowserViewSource;
+		window.BrowserViewSource = function(...aArgs) {
+			TreeStyleTabService.handleNewTabFromCurrent(aArgs[0]);
+			return this.__treestyletab__BrowserViewSource.apply(this, aArgs);
+		};
+
+		BrowserSearch.__treestyletab__loadSearch = BrowserSearch._loadSearch;
+		BrowserSearch._loadSearch = function(aSearchText, aUseNewTab, aPurpose) {
+			TreeStyleTabService.onBeforeBrowserSearch(aSearchText, aUseNewTab);
+			return this.__treestyletab__loadSearch.call(this, aSearchText, aUseNewTab, aPurpose);
+		};
+
+		window.__treestyletab__openLinkIn = window.openLinkIn;
+		window.openLinkIn = function(aUrl, aWhere, aParams) {
+			TreeStyleTabService.onBeforeOpenLinkWithTab(gBrowser.selectedTab, aParams.fromChrome);
+			return this.__treestyletab__openLinkIn.call(this, aUrl, aWhere, aParams);
+		};
 
 		[
-			'window.permaTabs.utils.wrappedFunctions["window.contentAreaClick"]',
-			'window.__contentAreaClick',
-			'window.__ctxextensions__contentAreaClick',
-			'window.contentAreaClick'
-		].forEach(function(aName) {
-			var func = this._getFunction(aName);
+			{ owner: window.permaTabs && window.permaTabs.utils && window.permaTabs.utils.wrappedFunctions,
+			  name:  'window.contentAreaClick' },
+			{ owner: window,
+			  name:  '__contentAreaClick' },
+			{ owner: window,
+			  name:  '__ctxextensions__contentAreaClick' },
+			{ owner: window,
+			  name:  'contentAreaClick' }
+		].forEach(function(aTarget) {
+			var name = aTarget.name;
+			var owner = aTarget.owner;
+			var func = owner && owner[name];
 			var source = func && func.toString();
 			if (!func ||
 				!/^\(?function contentAreaClick/.test(source) ||
@@ -221,20 +249,19 @@ var TreeStyleTabWindowHelper = {
 				// (calls for the function is not included by Firefox default.)
 				!/(openNewTabWith\()/.test(source))
 				return;
-			TreeStyleTabUtils.doPatching(func, aName, function(aName, aSource) {
-				return eval(aName+' = '+aSource.replace(
-					/(openNewTabWith\()/g,
-					'TreeStyleTabService.onBeforeOpenNewTabByThirdParty(event.target.ownerDocument.defaultView); $1'
-				));
-			}, 'TreeStyleTab');
+			let original = '__treestyletab__' + name;
+			owner[original] = owner[name];
+			owner[name] = function(aEvent, aIsPanelClick, ...aArgs) {
+				TreeStyleTabService.onBeforeOpenNewTabByThirdParty(aEvent.target.ownerDocument.defaultView);
+				return this[original].apply(this, [aEvent, aIsPanelClick].concat(aArgs));
+			};
 		}, this);
 
-		TreeStyleTabUtils.doPatching(window.duplicateTabIn, 'window.duplicateTabIn', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'{',
-				'{ gBrowser.treeStyleTab.onBeforeTabDuplicate(aTab, where, delta); '
-			));
-		}, 'treeStyleTab');
+		window.__treestyletab__duplicateTabIn = window.duplicateTabIn;
+		window.duplicateTabIn = function(aTab, where, delta) {
+			gBrowser.treeStyleTab.onBeforeTabDuplicate(aTab, where, delta);
+			return window.__treestyletab__duplicateTabIn.call(this, aTab, where, delta);
+		};
 
 		[
 			'permaTabs.utils.wrappedFunctions["window.BrowserHomeClick"]',
@@ -252,89 +279,82 @@ var TreeStyleTabWindowHelper = {
 			}, 'TreeStyleTab');
 		}, this);
 
-		TreeStyleTabUtils.doPatching(FeedHandler.loadFeed, 'FeedHandler.loadFeed', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'openUILink(',
-				'TreeStyleTabService.onBeforeViewMedia(event, gBrowser); $&'
-			));
-		}, 'TreeStyleTab');
+		FeedHandler.__treestyletab__loadFeed = FeedHandler.loadFeed;
+		FeedHandler.loadFeed = function(aHref, aEvent) {
+			TreeStyleTabService.onBeforeViewMedia(aEvent, gBrowser);
+			return this.__treestyletab__loadFeed.call(this, aHref, aEvent);
+		};
 
 		if ('showNavToolbox' in FullScreen) { // for Firefox 40 or later
-			TreeStyleTabUtils.doPatching(FullScreen.showNavToolbox, 'FullScreen.showNavToolbox', function(aName, aSource) {
-				return eval(aName+' = '+aSource.replace(
-					'this._isChromeCollapsed = false;',
-					'gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_FULLSCREEN); $&'
-				));
-			}, 'treeStyleTab');
-			TreeStyleTabUtils.doPatching(FullScreen.hideNavToolbox, 'FullScreen.hideNavToolbox', function(aName, aSource) {
-				return eval(aName+' = '+aSource.replace(
-					'this._isChromeCollapsed = true;',
-					'gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_FULLSCREEN); $&'
-				));
-			}, 'treeStyleTab');
+			FullScreen.__treestyletab__showNavToolbox = FullScreen.showNavToolbox;
+			FullScreen.showNavToolbox = function(...aArgs) {
+				var beforeCollapsed = this._isChromeCollapsed;
+				var retVal = this.__treestyletab__showNavToolbox.apply(this, aArgs);
+				if (beforeCollapsed !== this._isChromeCollapsed)
+					gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_FULLSCREEN);
+				return retVal;
+			};
+
+			FullScreen.__treestyletab__hideNavToolbox = FullScreen.hideNavToolbox;
+			FullScreen.hideNavToolbox = function(...aArgs) {
+				var beforeCollapsed = this._isChromeCollapsed;
+				var retVal = this.__treestyletab__hideNavToolbox.apply(this, aArgs);
+				if (beforeCollapsed !== this._isChromeCollapsed)
+					gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_FULLSCREEN);
+				return retVal;
+			};
 		}
 		else if ('mouseoverToggle' in FullScreen) { // for Firefox 39 or older
-			TreeStyleTabUtils.doPatching(FullScreen.mouseoverToggle, 'FullScreen.mouseoverToggle', function(aName, aSource) {
-				return eval(aName+' = '+aSource.replace(
-					'this._isChromeCollapsed = !aShow;',
-					'gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_FULLSCREEN); $&'
-				));
-			}, 'treeStyleTab');
-		}
-
-		TreeStyleTabUtils.doPatching(FullScreen.toggle, 'FullScreen.toggle', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'if (enterFS) {',
-				'gBrowser.treeStyleTab.onBeforeFullScreenToggle(enterFS); $&'
-			));
-		}, 'treeStyleTab');
-
-		TreeStyleTabUtils.doPatching(PrintUtils.printPreview, 'PrintUtils.printPreview', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'{',
-				'{ TreeStyleTabService.onPrintPreviewEnter();'
-			));
-		}, 'TreeStyleTab');
-		TreeStyleTabUtils.doPatching(PrintUtils.exitPrintPreview, 'PrintUtils.exitPrintPreview', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'{',
-				'{ TreeStyleTabService.onPrintPreviewExit();'
-			));
-		}, 'TreeStyleTab');
-
-		if ('TabsOnTop' in window) {
-			TreeStyleTabUtils.doPatching(TabsOnTop.syncUI, 'TabsOnTop.syncUI', function(aName, aSource) {
-				return eval(aName+' = '+aSource.replace(
-					/(\}\)?)$/,
-					'gBrowser.treeStyleTab.onTabsOnTopSyncCommand(enabled); $&'
-				));
-			}, 'treeStyleTab');
+			FullScreen.__treestyletab__mouseoverToggle = FullScreen.mouseoverToggle;
+			FullScreen.mouseoverToggle = function(...aArgs) {
+				var beforeCollapsed = this._isChromeCollapsed;
+				var retVal = this.__treestyletab__mouseoverToggle.apply(this, aArgs);
+				if (beforeCollapsed !== this._isChromeCollapsed)
+					gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_FULLSCREEN);
+				return retVal;
+			};
 		}
 
-		if ('SidebarUI' in window) { // for Firefox 39 or later
-			SidebarUI.__treestyletab__show = SidebarUI.show;
-			SidebarUI.show = function(...aArgs) {
-				return this.__treestyletab__show.apply(this, aArgs)
-						.then(function(aResult) {
+		FullScreen.__treestyletab__toggle = FullScreen.toggle;
+		FullScreen.toggle = function(...aArgs) {
+			var enterFS = window.fullScreen;
+			gBrowser.treeStyleTab.onBeforeFullScreenToggle(enterFS);
+			return this.__treestyletab__toggle.apply(this, aArgs);
+		};
+
+		PrintUtils.__treestyletab__printPreview = PrintUtils.printPreview;
+		PrintUtils.printPreview = function(...aArgs) {
+			TreeStyleTabService.onPrintPreviewEnter();
+			return this.__treestyletab__printPreview.apply(this, aArgs);
+		};
+		PrintUtils.__treestyletab__exitPrintPreview = PrintUtils.exitPrintPreview;
+		PrintUtils.exitPrintPreview = function(...aArgs) {
+			TreeStyleTabService.onPrintPreviewExit();
+			return this.__treestyletab__exitPrintPreview.apply(this, aArgs);
+		};
+
+		SidebarUI.__treestyletab__show = SidebarUI.show;
+		SidebarUI.show = function(...aArgs) {
+			var opened = this.isOpen;
+			var width = this.browser.boxObject.width;
+			return this.__treestyletab__show.apply(this, aArgs)
+					.then((function(aResult) {
+						if (opened !== this.isOpen ||
+							width !== this.browser.boxObject.width)
 							gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_TOGGLE_SIDEBAR);
-							return aResult;
-						});
-			};
-			SidebarUI.__treestyletab__hide = SidebarUI.hide;
-			SidebarUI.hide = function(...aArgs) {
-				var retVal = this.__treestyletab__hide.apply(this, aArgs);
+						return aResult;
+					}).bind(this));
+		};
+		SidebarUI.__treestyletab__hide = SidebarUI.hide;
+		SidebarUI.hide = function(...aArgs) {
+			var opened = this.isOpen;
+			var width = this.browser.boxObject.width;
+			var retVal = this.__treestyletab__hide.apply(this, aArgs);
+			if (opened !== this.isOpen ||
+				width !== this.browser.boxObject.width)
 				gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_TOGGLE_SIDEBAR);
-				return retVal;
-			};
-		}
-		else if ('toggleSidebar' in window) { // for Firefox 38 or older
-			TreeStyleTabUtils.doPatching(window.toggleSidebar, 'window.toggleSidebar', function(aName, aSource) {
-				return eval(aName+' = '+aSource.replace(
-					'{',
-					'{ gBrowser.treeStyleTab.updateFloatingTabbar(gBrowser.treeStyleTab.kTABBAR_UPDATE_BY_TOGGLE_SIDEBAR);'
-				));
-			}, 'treeStyleTab');
-		}
+			return retVal;
+		};
 	},
 	_splitFunctionNames : function TSTWH__splitFunctionNames(aString)
 	{
@@ -361,6 +381,8 @@ var TreeStyleTabWindowHelper = {
  
 	initToolbarItems : function TSTWH_initToolbarItems() 
 	{
+		let { ReferenceCounter } = Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js', {});
+
 		var searchbar = document.getElementById('searchbar');
 		if (searchbar &&
 			searchbar.doSearch &&
@@ -375,35 +397,47 @@ var TreeStyleTabWindowHelper = {
 		}
 
 		var goButton = document.getElementById('urlbar-go-button');
-		if (goButton)
+		if (goButton) {
 			goButton.parentNode.addEventListener('click', this.service, true);
+			ReferenceCounter.add('goButton.parentNode,click,this.service,true');
+		}
 
 		var tabbar = this.service.getTabStrip(this.service.browser);
 		tabbar.addEventListener('click', this.service, true);
+		ReferenceCounter.add('tabbar,click,this.service,true');
 
 		var newTabButton = document.getElementById('new-tab-button');
-		const nsIDOMNode = Ci.nsIDOMNode;
+		var nsIDOMNode = Ci.nsIDOMNode;
 		if (newTabButton &&
-			!(tabbar.compareDocumentPosition(newTabButton) & nsIDOMNode.DOCUMENT_POSITION_CONTAINED_BY))
+			!(tabbar.compareDocumentPosition(newTabButton) & nsIDOMNode.DOCUMENT_POSITION_CONTAINED_BY)) {
 			newTabButton.parentNode.addEventListener('click', this.service, true);
+			ReferenceCounter.add('newTabButton.parentNode,click,this.service,true');
+		}
 
 		this.service.updateAllTabsButton(gBrowser);
 	},
  
 	destroyToolbarItems : function TSTWH_destroyToolbarItems() 
 	{
+		let { ReferenceCounter } = Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js', {});
+
 		var goButton = document.getElementById('urlbar-go-button');
-		if (goButton)
-			goButton.parentNode.removeEventListener('click', this, true);
+		if (goButton) {
+			goButton.parentNode.removeEventListener('click', this.service, true);
+			ReferenceCounter.remove('goButton.parentNode,click,this.service,true');
+		}
 
 		var tabbar = this.service.getTabStrip(this.service.browser);
 		tabbar.removeEventListener('click', this.service, true);
+		ReferenceCounter.remove('tabbar,click,this.service,true');
 
 		var newTabButton = document.getElementById('new-tab-button');
-		const nsIDOMNode = Ci.nsIDOMNode;
+		var nsIDOMNode = Ci.nsIDOMNode;
 		if (newTabButton &&
-			!(tabbar.compareDocumentPosition(newTabButton) & Ci.nsIDOMNode.DOCUMENT_POSITION_CONTAINED_BY))
+			!(tabbar.compareDocumentPosition(newTabButton) & Ci.nsIDOMNode.DOCUMENT_POSITION_CONTAINED_BY)) {
 			newTabButton.parentNode.removeEventListener('click', this.service, true);
+			ReferenceCounter.remove('newTabButton.parentNode,click,this.service,true');
+		}
 
 		var allTabsButton = document.getElementById('alltabs-button');
 		if (allTabsButton && allTabsButton.hasChildNodes())
@@ -498,27 +532,26 @@ var TreeStyleTabWindowHelper = {
 			));
 		}, 'treeStyleTab');
 
-		TreeStyleTabUtils.doPatching(b.removeCurrentTab, 'b.removeCurrentTab', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'{',
-				'{ if (!this.treeStyleTab.warnAboutClosingTabSubtreeOf(this.selectedTab)) return;'
-			));
-		}, 'treeStyleTab');
+		b.__treestyletab__removeCurrentTab = b.removeCurrentTab;
+		b.removeCurrentTab = function(...aArgs) {
+			if (!this.treeStyleTab.warnAboutClosingTabSubtreeOf(this.selectedTab))
+				return;
+			return this.__treestyletab__removeCurrentTab.apply(this, aArgs);
+		};
 	},
  
 	initTabbarMethods : function TSTWH_initTabbarMethods(aTabBrowser) 
 	{
 		var b = aTabBrowser;
 
-		TreeStyleTabUtils.doPatching(b.mTabContainer.advanceSelectedTab, 'b.mTabContainer.advanceSelectedTab', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'{',
-				'{\n' +
-				'  var treeStyleTab = TreeStyleTabService.getTabBrowserFromChild(this).treeStyleTab;\n' +
-				'  if (treeStyleTab.handleAdvanceSelectedTab(arguments[0], arguments[1]))\n' +
-				'    return;'
-			));
-		}, 'treeStyleTab.handleAdvanceSelectedTab');
+		if (!b.mTabContainer.__treestyletab__advanceSelectedTab)
+			b.mTabContainer.__treestyletab__advanceSelectedTab = b.mTabContainer.advanceSelectedTab;
+		if (b.mTabContainer.advanceSelectedTab.toString() === b.mTabContainer.__treestyletab__advanceSelectedTab.toString())
+			b.mTabContainer.advanceSelectedTab = function(...aArgs) {
+				if (b.treeStyleTab.handleAdvanceSelectedTab(aArgs[0], aArgs[1]))
+					return;
+				return this.__treestyletab__advanceSelectedTab.apply(this, aArgs);
+			};
 
 		TreeStyleTabUtils.doPatching(b.mTabContainer._notifyBackgroundTab, 'b.mTabContainer._notifyBackgroundTab', function(aName, aSource) {
 			return eval(aName+' = '+aSource.replace(
@@ -556,6 +589,14 @@ var TreeStyleTabWindowHelper = {
 			));
 		}, 'TreeStyleTabService.getTabBrowserFromChild');
 
+		TreeStyleTabUtils.doPatching(b.tabContainer._getDragTargetTab, 'b.tabContainer._getDragTargetTab', function(aName, aSource) {
+			return eval(aName+' = '+aSource.replace(
+				/\.screenX/g, '[this.treeStyleTab.screenPositionProp]'
+			).replace(
+				/\.width/g, '[this.treeStyleTab.sizeProp]'
+			));
+		}, 'treeStyleTab');
+
 		TreeStyleTabUtils.doPatching(b.tabContainer._getDropIndex, 'b.tabContainer._getDropIndex', function(aName, aSource) {
 			return eval(aName+' = '+aSource.replace(
 				/\.screenX/g, '[this.treeStyleTab.screenPositionProp]'
@@ -573,14 +614,11 @@ var TreeStyleTabWindowHelper = {
 				if (!scrollbox.__treestyletab__ensureElementIsVisible) {
 				scrollbox.__treestyletab__ensureElementIsVisible = scrollbox.ensureElementIsVisible;
 				scrollbox.ensureElementIsVisible = function(...aArgs) {
-					var treeStyleTab = TreeStyleTabService.getTabBrowserFromChild(this).treeStyleTab;
-					if (treeStyleTab) {
-						if (treeStyleTab.shouldCancelEnsureElementIsVisible())
-							return;
-						let shouldScrollNow = aArgs[1] === false;
-						if (treeStyleTab.animationEnabled && !shouldScrollNow)
-							return treeStyleTab.scrollToTab(aArgs[0]);
-					}
+					if (b.treeStyleTab.shouldCancelEnsureElementIsVisible())
+						return;
+					let shouldScrollNow = aArgs[1] === false;
+					if (b.treeStyleTab.animationEnabled && !shouldScrollNow)
+						return b.treeStyleTab.scrollToTab(aArgs[0]);
 					this.__treestyletab__ensureElementIsVisible.apply(this, aArgs);
 				};
 			}
diff --git a/content/treestyletab/windowHelperHacks.js b/content/treestyletab/windowHelperHacks.js
index fd28c5d..ba3e709 100644
--- a/content/treestyletab/windowHelperHacks.js
+++ b/content/treestyletab/windowHelperHacks.js
@@ -318,33 +318,37 @@ TreeStyleTabWindowHelper.overrideExtensionsPreInit = function TSTWH_overrideExte
 	// https://addons.mozilla.org/firefox/addon/748
 	if (TreeStyleTabUtils.getTreePref('compatibility.Greasemonkey')) {
 		try {
-			let hitchModule = Components.utils.import('resource://greasemonkey/util/hitch.js', {});
-			let hitch = hitchModule.hitch;
-			if (hitch.toSource().indexOf('TreeStyleTabService') < 0) {
-				let ns = {};
-				Components.utils.import('resource://greasemonkey/third-party/getChromeWinForContentWin.js', ns);
-				let getChromeWinForContentWin = ns.getChromeWinForContentWin;
-				hitchModule.hitch = function(aObject, aMethod) {
-					if (typeof aMethod == 'function' &&
-						aMethod.toSource().indexOf('function openInTab') > -1) {
-						let originalOpenInTab = aMethod;
-						/**
-						 * This function must be replaced on scripts in "chrome:" URL, like this.
-						 * Otherwise the original openInTab() will raise violation error.
-						 * Don't move this hack into JS code modules with "resource:" URL.
-						 */
-						aMethod = function openInTab(aSafeContentWindow, aURL, aLoadInBackgtound) {
-							let chrome = getChromeWinForContentWin(aSafeContentWindow);
-							if (chrome && chrome.TreeStyleTabService)
-								chrome.TreeStyleTabService.readyToOpenChildTabNow(aSafeContentWindow);
-							return originalOpenInTab.apply(this, arguments);
-						};
-					}
-					return hitch.apply(this, arguments);
+			if ('GM_BrowserUI' in window &&
+				typeof GM_BrowserUI.openInTab == 'function') {
+				window.messageManager.removeMessageListener('greasemonkey:open-in-tab', GM_BrowserUI.openInTab);
+				let originalOpenInTab = GM_BrowserUI.openInTab;
+				let originalTabs = [];
+				GM_BrowserUI.openInTab = function(aMessage, ...aArgs) {
+					if (originalTabs.length === 0)
+						originalTabs = Array.slice(gBrowser.tabContainer.childNodes, 0);
+					var owner = aMessage.target;
+					var retVal = originalOpenInTab.apply(this, [aMessage].concat(aArgs));
+					window.setTimeout(function() {
+						window.setTimeout(function() {
+							if (originalTabs.length === 0)
+								return;
+							var currentTabs = Array.slice(gBrowser.tabContainer.childNodes, 0);
+							var parent = gBrowser.treeStyleTab.getTabFromBrowser(owner);
+							var insertAtFirst = TreeStyleTabUtils.getTreePref('insertNewChildAt') == sv.kINSERT_FISRT;
+							var firstChild = gBrowser.treeStyleTab.getFirstChildTab(parent);
+							currentTabs.forEach(function(aTab) {
+								if (originalTabs.indexOf(aTab) >= 0)
+									return;
+								gBrowser.treeStyleTab.attachTabTo(aTab, parent, {
+									insertBefore : insertAtFirst ? firstChild : null
+								});
+							});
+							originalTabs = [];
+						}, 0);
+					}, 0);
+					return retVal;
 				};
-				Components.utils.import('resource://greasemonkey/util.js', ns);
-				if (ns.GM_util)
-					ns.GM_util.hitch = hitchModule.hitch;
+				window.messageManager.addMessageListener('greasemonkey:open-in-tab', GM_BrowserUI.openInTab);
 			}
 		}
 		catch(e) {
diff --git a/defaults/preferences/treestyletab.js b/defaults/preferences/treestyletab.js
index 168311f..788b7e0 100644
--- a/defaults/preferences/treestyletab.js
+++ b/defaults/preferences/treestyletab.js
@@ -250,7 +250,7 @@ pref("extensions.treestyletab.maxTreeLevel.vertical",   999);
  * So, even if you enlarge "maxTreeLevel" prefs, you won't see tabs with new
  * indentation.
  */
-pref("extensions.treestyletab.maxTreeLevel.phisical", false);
+pref("extensions.treestyletab.maxTreeLevel.physical", false);
 
 /**
  * Indentation size for one tree level, in pixels. 
@@ -703,3 +703,13 @@ pref("extensions.treestyletab.compatibility.TotalToolbar", true);
  */
 pref("extensions.treestyletab.prefsVersion", 0);
 
+/**
+ * Flags to activate debug dumps for each module.
+ */
+pref("extensions.treestyletab.debug.all", false);
+pref("extensions.treestyletab.debug.autoHide", false);
+pref("extensions.treestyletab.debug.base", false);
+pref("extensions.treestyletab.debug.browser", false);
+pref("extensions.treestyletab.debug.browserUIShowHideObserver", false);
+pref("extensions.treestyletab.debug.contentBridge", false);
+pref("extensions.treestyletab.debug.tabbarDNDObserver", false);
diff --git a/install.rdf b/install.rdf
index d293fcd..69f92be 100644
--- a/install.rdf
+++ b/install.rdf
@@ -5,7 +5,7 @@
   <RDF:Description RDF:about="urn:mozilla:install-manifest"
                    em:id="treestyletab at piro.sakura.ne.jp"
                    em:name="Tree Style Tab"
-                   em:version="0.15.20150902901"
+                   em:version="0.16.2015111001"
                    em:creator="YUKI "Piro" Hiroshi"
                    em:description="Show tabs like a tree."
                    em:homepageURL="http://piro.sakura.ne.jp/xul/_treestyletab.html.en"
@@ -235,7 +235,7 @@
     <em:targetApplication>
       <RDF:Description em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
                        em:minVersion="38.0"
-                       em:maxVersion="44.0a1" />
+                       em:maxVersion="45.0a1" />
     </em:targetApplication>
   </RDF:Description>
 </RDF:RDF>
diff --git a/locale/en-US/treestyletab/treestyletab.dtd b/locale/en-US/treestyletab/treestyletab.dtd
index 09f93f9..6a63bc7 100644
--- a/locale/en-US/treestyletab/treestyletab.dtd
+++ b/locale/en-US/treestyletab/treestyletab.dtd
@@ -7,8 +7,8 @@
 <!ENTITY config.tabs.appearance "Appearance">
 
 <!ENTITY config.tabbar.position.caption "Tab bar position">
-<!ENTITY config.tabbar.position.left    "Leftside">
-<!ENTITY config.tabbar.position.right   "Rightside">
+<!ENTITY config.tabbar.position.left    "Left">
+<!ENTITY config.tabbar.position.right   "Right">
 <!ENTITY config.tabbar.position.top     "Top (Firefox default)">
 <!ENTITY config.tabbar.position.bottom  "Bottom">
 <!ENTITY config.tabbar.invertClosebox.left  "Show closebox at leftside in each tab">
diff --git a/modules/ReferenceCounter.js b/modules/ReferenceCounter.js
new file mode 100644
index 0000000..b57318c
--- /dev/null
+++ b/modules/ReferenceCounter.js
@@ -0,0 +1,42 @@
+/**
+ * How to use:
+ *
+ *  1. Insert "ReferenceCounter.add('unique key'); after "addEventListener()"
+ *  2. Insert "ReferenceCounter.remove('unique key'); after "removeEventListener()"
+ *  3. Open and close windows multiple times.
+ *  4. Go to the browser console and run the script:
+ *     (function() { let { ReferenceCounter } = Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js', {}); return ReferenceCounter.report() })();
+ *
+ * Expected result for good case:
+ *
+ *   Blank array is returned.
+ *
+ * Expected result for bad case:
+ *
+ *   Not-removed counters are reported as the elements of the returned array.
+ */
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ['ReferenceCounter'];
+
+var ReferenceCounter = {
+	_listeners: {},
+	add: function(aKey) {
+		this._listeners[aKey] = this._listeners[aKey] || 0;
+		this._listeners[aKey]++;
+	},
+	remove: function(aKey) {
+		this._listeners[aKey] = this._listeners[aKey] || 0;
+		this._listeners[aKey]--;
+	},
+	report: function() {
+		var keys = [];
+		Object.keys(this._listeners).forEach(function(aKey) {
+			if (this._listeners[aKey] <= 1)
+				return;
+			keys.push(aKey+'('+this._listeners[aKey]+')');
+		}, this);
+		return keys;
+	}
+};
diff --git a/modules/autoHide.js b/modules/autoHide.js
index 6665e8a..c6eb9e0 100644
--- a/modules/autoHide.js
+++ b/modules/autoHide.js
@@ -34,9 +34,7 @@
  *
  * ***** END LICENSE BLOCK ******/
  
-const EXPORTED_SYMBOLS = ['AutoHideBrowser', 'AutoHideWindow'];
-
-const DEBUG = false;
+var EXPORTED_SYMBOLS = ['AutoHideBrowser', 'AutoHideWindow'];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
@@ -46,6 +44,7 @@ Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
 Cu.import('resource://treestyletab-modules/constants.js');
+Cu.import('resource://treestyletab-modules/ReferenceCounter.js');
 
 XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
 
@@ -59,7 +58,7 @@ XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
 });
 
 
-const AutoHideConstants = Object.freeze(inherit(TreeStyleTabConstants, {
+var AutoHideConstants = Object.freeze(inherit(TreeStyleTabConstants, {
 	kMODE : 'treestyletab-tabbar-autohide-mode', 
 	kMODE_DISABLED : 0,
 	kMODE_HIDE     : 1,
@@ -355,11 +354,21 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 
 		if (!(aReason & this.kSHOWHIDE_BY_API)) {
 			b.addEventListener('dragover', this, true);
+			ReferenceCounter.add('b,dragover,AHW,true');
 			b.addEventListener('dragleave', this, true);
+			ReferenceCounter.add('b,dragleave,AHW,true');
 			sv.tabStripPlaceHolder.addEventListener('mousedown', this, true);
+			ReferenceCounter.add('tabStripPlaceHolder,mousedown,AHW,true');
 			sv.tabStripPlaceHolder.addEventListener('mouseup', this, true);
+			ReferenceCounter.add('tabStripPlaceHolder,mouseup,AHW,true');
 			sv.tabStrip.addEventListener('mousedown', this, true);
-			sv.tabStrip.addEventListener('mouseup', this, true);
+			ReferenceCounter.add('tabStrip,mousedown,AHW,true');
+			w.addEventListener('mouseup', this, true);
+			ReferenceCounter.add('w,mouseup,AHW,true');
+			w.addEventListener('dragend', this, true);
+			ReferenceCounter.add('w,dragend,AHW,true');
+			w.addEventListener('drop', this, true);
+			ReferenceCounter.add('w,drop,AHW,true');
 			if (this.shouldListenMouseMove)
 				this.startListenMouseMove();
 			if (b == w.gBrowser && sv.shouldListenKeyEventsForAutoHide)
@@ -368,7 +377,9 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 			this.notifyStatusToAllTabs();
 		}
 		w.addEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
+		ReferenceCounter.add('w,kEVENT_TYPE_PRINT_PREVIEW_ENTERED,AHW,false');
 		w.addEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
+		ReferenceCounter.add('w,kEVENT_TYPE_PRINT_PREVIEW_EXITED,AHW,false');
 
 		this.updateTransparency();
 
@@ -394,11 +405,21 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 
 		if (this.userActionListening) {
 			b.removeEventListener('dragover', this, true);
+			ReferenceCounter.remove('b,dragover,AHW,true');
 			b.removeEventListener('dragleave', this, true);
+			ReferenceCounter.remove('b,dragleave,AHW,true');
 			sv.tabStripPlaceHolder.removeEventListener('mousedown', this, true);
+			ReferenceCounter.remove('tabStripPlaceHolder,mousedown,AHW,true');
 			sv.tabStripPlaceHolder.removeEventListener('mouseup', this, true);
+			ReferenceCounter.remove('tabStripPlaceHolder,mouseup,AHW,true');
 			sv.tabStrip.removeEventListener('mousedown', this, true);
-			sv.tabStrip.removeEventListener('mouseup', this, true);
+			ReferenceCounter.remove('tabStrip,mousedown,AHW,true');
+			w.removeEventListener('mouseup', this, true);
+			ReferenceCounter.remove('w,mouseup,AHW,true');
+			w.removeEventListener('dragend', this, true);
+			ReferenceCounter.remove('w,dragend,AHW,true');
+			w.removeEventListener('drop', this, true);
+			ReferenceCounter.remove('w,drop,AHW,true');
 			this.endListenMouseMove();
 			if (b == w.gBrowser)
 				w.TreeStyleTabService.endListenKeyEventsFor(sv.LISTEN_FOR_AUTOHIDE);
@@ -406,7 +427,9 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 			this.notifyStatusToAllTabs();
 		}
 		w.removeEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
+		ReferenceCounter.remove('w,kEVENT_TYPE_PRINT_PREVIEW_ENTERED,AHW,false');
 		w.removeEventListener(sv.kEVENT_TYPE_PRINT_PREVIEW_EXITED, this, false);
+		ReferenceCounter.remove('w,kEVENT_TYPE_PRINT_PREVIEW_EXITED,AHW,false');
 
 		this.updateTransparency();
 
@@ -463,10 +486,15 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 			return;
 
 		this.screen.addEventListener('mousemove', this, true);
+		ReferenceCounter.add('screen,mousemove,AHW,true');
 		this.treeStyleTab.tabStripPlaceHolder.addEventListener('mousemove', this, true);
+		ReferenceCounter.add('tabStripPlaceHolder,mousemove,AHW,true');
 		this.treeStyleTab.tabStrip.addEventListener('mousemove', this, true);
+		ReferenceCounter.add('tabStrip,mousemove,AHW,true');
 		this.toggler.addEventListener('mousemove', this, true);
+		ReferenceCounter.add('toggler,mousemove,AHW,true');
 		this.window.addEventListener('TabRemotenessChange', this, false);
+		ReferenceCounter.add('window,TabRemotenessChange,AHW,false');
 
 		this.mouseMoveListening = true;
 
@@ -479,10 +507,15 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 			return;
 
 		this.screen.removeEventListener('mousemove', this, true);
+		ReferenceCounter.remove('screen,mousemove,AHW,true');
 		this.treeStyleTab.tabStripPlaceHolder.removeEventListener('mousemove', this, true);
+		ReferenceCounter.remove('tabStripPlaceHolder,mousemove,AHW,true');
 		this.treeStyleTab.tabStrip.removeEventListener('mousemove', this, true);
+		ReferenceCounter.remove('tabStrip,mousemove,AHW,true');
 		this.toggler.removeEventListener('mousemove', this, true);
+		ReferenceCounter.remove('toggler,mousemove,AHW,true');
 		this.window.removeEventListener('TabRemotenessChange', this, false);
+		ReferenceCounter.remove('window,TabRemotenessChange,AHW,false');
 
 		this.mouseMoveListening = false;
 
@@ -502,8 +535,17 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
  
 	showHideOnMouseMove : function AHB_showHideOnMouseMove(aCoordinates) 
 	{
+		var sv = this.treeStyleTab;
+		var b  = this.browser;
+		var w  = this.window;
+
+		var exapndedByUnknownReason = (
+				this.expanded &&
+				!(this.showHideReason & this.kSHOWN_BY_ANY_REASON)
+			);
 		var position = this.getMousePosition(aCoordinates);
-		if (DEBUG) {
+
+		if (utils.isDebugging('autoHide')) {
 			let humanReadablePosition = [];
 			if (position & this.MOUSE_POSITION_OUTSIDE)
 				humanReadablePosition.push('outside');
@@ -513,20 +555,29 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 				humanReadablePosition.push('near');
 			if (position & this.MOUSE_POSITION_SENSITIVE)
 				humanReadablePosition.push('sensitive');
+			let extraInfo = [];
+			if (sv.isPopupShown())
+				extraInfo.push('popupshown');
+			if (exapndedByUnknownReason)
+				extraInfo.push('expanded-by-unknown');
+			if (this.lastMouseDownTarget)
+				extraInfo.push('mousedown');
 			dump('showHideOnMouseMove: ' +
 			       '('+aCoordinates.screenX + ', ' + aCoordinates.screenY + ') => ' +
-			       humanReadablePosition.join(', ') + '\n');
+			       humanReadablePosition.join(', ') +
+			       (extraInfo.length ? ('[' + extraInfo.join(', ') + ']') : '') +
+			       '\n');
 		}
-		if (position == this.MOUSE_POSITION_UNKNOWN)
+
+		if (sv.isPopupShown() ||
+			exapndedByUnknownReason ||
+			this.lastMouseDownTarget ||
+			position == this.MOUSE_POSITION_UNKNOWN)
 			return;
 
 		this.cancelShowHideOnMouseMove();
 		this.showHideContentsAreaScreen();
 
-		var sv = this.treeStyleTab;
-		var b  = this.browser;
-		var w  = this.window;
-
 		var shouldShow = position & this.MOUSE_POSITION_SENSITIVE;
 		if (this.expanded) { // currently shown, let's hide it.
 			if (shouldShow) {
@@ -839,7 +890,7 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 			this.showHideReason = aReason || this.showHideReason || this.kSHOWN_BY_UNKNOWN;
 		}
 
-		if (DEBUG) {
+		if (utils.isDebugging('autoHide')) {
 			let givenReason = this._getHumanReadableReason(aReason);
 			let unifiedReason = this._getHumanReadableReason(this.showHideReason);
 			if (this.expanded)
@@ -1091,14 +1142,16 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 				if (!this.window.TreeStyleTabService.shouldApplyNewPref('tabbar.autoHide.mode'))
 					return;
 				this.browser.setAttribute(this.kMODE+'-normal', value);
-				this.updateMode(value);
+				if (!this.window.fullScreen)
+					this.updateMode(value);
 				return;
 
 			case 'extensions.treestyletab.tabbar.autoHide.mode.fullscreen':
 				if (!this.window.TreeStyleTabService.shouldApplyNewPref('tabbar.autoHide.mode.fullscreen'))
 					return;
 				this.browser.setAttribute(this.kMODE+'-fullscreen', value);
-				this.updateMode(value);
+				if (this.window.fullScreen)
+					this.updateMode(value);
 				return;
 
 			case 'extensions.treestyletab.tabbar.autoShow.mousemove':
@@ -1156,6 +1209,11 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 				return this.onMouseDown(aEvent);
 
 			case 'mouseup':
+			// Note, we must handle "drop" event also to handle the end
+			// of drag-and-drop of a tab due to the bug:
+			// https://bugzilla.mozilla.org/show_bug.cgi?id=460801
+			case 'dragend':
+			case 'drop':
 				return this.onMouseUp(aEvent);
 
 			case 'mousemove':
@@ -1271,7 +1329,8 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 	onMouseUp : function AHB_onMouseUp(aEvent) 
 	{
 		var sv = this.treeStyleTab;
-		if (aEvent.originalTarget &&
+		if (this.isResizing &&
+			aEvent.originalTarget &&
 			sv.evaluateXPath(
 				'ancestor-or-self::*[@class="'+sv.kSPLITTER+'"]',
 				aEvent.originalTarget,
@@ -1291,15 +1350,7 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 			/^(scrollbar|thumb|slider|scrollbarbutton)$/i.test(this.lastMouseDownTarget || ''))
 			return true;
 
-		if (
-			!aEvent.shiftKey &&
-			!sv.isPopupShown() &&
-			(
-				!this.expanded ||
-				this.showHideReason & this.kSHOWN_BY_ANY_REASON
-			) &&
-			!this.lastMouseDownTarget
-			)
+		if (!aEvent.shiftKey)
 			this.showHideOnMouseMove(aEvent);
 		return true;
 	},
@@ -1421,14 +1472,23 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 		this.onPrefChange('extensions.treestyletab.tabbar.autoHide.contentAreaScreen.enabled');
 
 		b.mTabContainer.addEventListener('TabOpen', this, false);
+		ReferenceCounter.add('mTabContainer,TabOpen,AHW,false');
 		b.mTabContainer.addEventListener('TabClose', this, false);
+		ReferenceCounter.add('mTabContainer,TabClose,AHW,false');
 		b.mTabContainer.addEventListener('TabMove', this, false);
+		ReferenceCounter.add('mTabContainer,TabMove,AHW,false');
 		b.mTabContainer.addEventListener('select', this, false);
+		ReferenceCounter.add('mTabContainer,select,AHW,false');
 		b.addEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGING, this, false);
+		ReferenceCounter.add('b,kEVENT_TYPE_TABBAR_POSITION_CHANGING,AHW,false');
 		b.addEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false);
+		ReferenceCounter.add('b,kEVENT_TYPE_TABBAR_POSITION_CHANGED,AHW,false');
 		b.addEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN, this, false);
+		ReferenceCounter.add('b,kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN,AHW,false');
 		b.addEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START, this, false);
+		ReferenceCounter.add('b,kEVENT_TYPE_TAB_FOCUS_SWITCHING_START,AHW,false');
 		b.addEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
+		ReferenceCounter.add('b,kEVENT_TYPE_TAB_FOCUS_SWITCHING_END,AHW,false');
 	},
  
 	destroy : function AHB_destroy() 
@@ -1439,14 +1499,23 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 		var sv = this.treeStyleTab;
 		var b  = this.browser;
 		b.mTabContainer.removeEventListener('TabOpen', this, false);
+		ReferenceCounter.remove('mTabContainer,TabOpen,AHW,false');
 		b.mTabContainer.removeEventListener('TabClose', this, false);
+		ReferenceCounter.remove('mTabContainer,TabClose,AHW,false');
 		b.mTabContainer.removeEventListener('TabMove', this, false);
+		ReferenceCounter.remove('mTabContainer,TabMove,AHW,false');
 		b.mTabContainer.removeEventListener('select', this, false);
+		ReferenceCounter.remove('mTabContainer,select,AHW,false');
 		b.removeEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGING, this, false);
+		ReferenceCounter.remove('b,kEVENT_TYPE_TABBAR_POSITION_CHANGING,AHW,false');
 		b.removeEventListener(sv.kEVENT_TYPE_TABBAR_POSITION_CHANGED, this, false);
+		ReferenceCounter.remove('b,kEVENT_TYPE_TABBAR_POSITION_CHANGED,AHW,false');
 		b.removeEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN, this, false);
+		ReferenceCounter.remove('b,kEVENT_TYPE_TAB_FOCUS_SWITCHING_KEY_DOWN,AHW,false');
 		b.removeEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_START, this, false);
+		ReferenceCounter.remove('b,kEVENT_TYPE_TAB_FOCUS_SWITCHING_START,AHW,false');
 		b.removeEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
+		ReferenceCounter.remove('b,kEVENT_TYPE_TAB_FOCUS_SWITCHING_END,AHW,false');
 
 		delete this.treeStyleTab;
 		delete this.browser;
@@ -1590,6 +1659,7 @@ AutoHideWindow.prototype = inherit(AutoHideBase.prototype, {
 
 		this.waitingForWindowReady = true;
 		this.window.addEventListener('SSWindowStateReady', this, false);
+		ReferenceCounter.add('window,SSWindowStateReady,AHW,false');
 		Services.obs.addObserver(this, 'browser-delayed-startup-finished', false);
 	},
  
@@ -1600,6 +1670,7 @@ AutoHideWindow.prototype = inherit(AutoHideBase.prototype, {
 
 		this.waitingForWindowReady = false;
 		this.window.removeEventListener('SSWindowStateReady', this, false);
+		ReferenceCounter.remove('window,SSWindowStateReady,AHW,false');
 		Services.obs.removeObserver(this, 'browser-delayed-startup-finished');
 	},
  
diff --git a/modules/base.js b/modules/base.js
index 3b0e385..778b454 100644
--- a/modules/base.js
+++ b/modules/base.js
@@ -34,7 +34,7 @@
  *
  * ***** END LICENSE BLOCK ******/
  
-const EXPORTED_SYMBOLS = ['TreeStyleTabBase']; 
+var EXPORTED_SYMBOLS = ['TreeStyleTabBase']; 
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
@@ -149,7 +149,8 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			this.overrideExtensions();
 		}
 		catch(e) {
-			dump(e+'\n');
+			if (utils.isDebugging('base'))
+				dump(e+'\n');
 		}
 	},
 	_initialized : false,
@@ -518,14 +519,15 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 
 		var message = 'ERROR: accessed after destruction!';
 		var error = new Error(message);
-		dump(message+'\n'+error.stack+'\n');
+		if (utils.isDebugging('base'))
+			dump(message+'\n'+error.stack.replace(/^/gm, '  ')+'\n');
 		throw error;
 	},
   
 	defaultErrorHandler : function TSTBase_defaultErrorHandler(aError) 
 	{
 		if (aError.stack)
-			Cu.reportError(aError.message+'\n'+aError.stack);
+			Cu.reportError(aError.message+'\n'+aError.stack.replace(/^/gm, '  '));
 		else
 			Cu.reportError(aError);
 	},
@@ -949,9 +951,9 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 	{
 		var strip = this.tabStrip;
 		if (!strip) {
-			if (DEBUG) {
+			if (utils.isDebugging('base')) {
 				dump('FAILED TO SET TABSTRIP ATTRIBUTE ' + aAttr + '=' + aValue + '\n');
-				dump((new Error()).stack + '\n');
+				dump((new Error()).stack.replace(/^/gm, '  ') + '\n');
 			}
 			return;
 		}
@@ -1508,7 +1510,9 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			refId = aInsertBefore.getAttribute(this.kID);
 		}
 
-		dump('Tree Style Tab: new child tab is requested.\n'+new Error().stack+'\n');
+		if (utils.isDebugging('base'))
+			dump('Tree Style Tab: new child tab is requested.\n'+
+			     new Error().stack.replace(/^/gm, '  ')+'\n');
 
 		ownerBrowser.treeStyleTab.readiedToAttachNewTab   = true;
 		ownerBrowser.treeStyleTab.readiedToAttachMultiple = aMultiple || false ;
@@ -1644,6 +1648,11 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			return false;
 
 		var ownerBrowser = this.getTabBrowserFromChild(browser);
+
+		if (ownerBrowser.treeStyleTab.readiedToAttachNewTab && utils.isDebugging('base'))
+			dump('Tree Style Tab: new child tab is canceled.\n'+
+			     new Error().stack.replace(/^/gm, '  ')+'\n');
+
 		ownerBrowser.treeStyleTab.readiedToAttachNewTab      = false;
 		ownerBrowser.treeStyleTab.readiedToAttachNewTabGroup = false;
 		ownerBrowser.treeStyleTab.readiedToAttachMultiple    = false;
@@ -1834,7 +1843,8 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 								aTab.label+'\n     '+
 								aTab.getAttribute(this.kID);
 					}, this).join('\n');
-				dump(message+'\n');
+				if (utils.isDebugging('base'))
+					dump(message+'\n');
 				break;
 			}
 
@@ -1846,7 +1856,8 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 								aTab.label+'\n     '+
 								aTab.getAttribute(this.kID);
 					}, this).join('\n');
-				dump(message+'\n');
+				if (utils.isDebugging('base'))
+					dump(message+'\n');
 			}
 
 			tabs.push(parentTab);
@@ -1993,7 +2004,8 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 								aTab.label+'\n     '+
 								aTab.getAttribute(this.kID);
 					}, this).join('\n');
-				dump(message+'\n');
+				if (utils.isDebugging('base'))
+					dump(message+'\n');
 				continue;
 			}
 			tabs.push(tab);
@@ -2077,19 +2089,8 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 		if (!aTab)
 			return null;
 
-		if (this.tabsHash) { // XPath-less implementation
-			let tabs = this.getDescendantTabs(aTab);
-			return tabs.length ? tabs[tabs.length-1] : null ;
-		}
-
-		var parent = aTab.getAttribute(this.kPARENT);
-		return this.evaluateXPath(
-			'following-sibling::xul:tab['+
-				(parent ? '@'+this.kPARENT+'="'+parent+'"' : 'not(@'+this.kPARENT+')' )+
-			'][1]/preceding-sibling::xul:tab[1][not(@'+this.kID+'="'+aTab.getAttribute(this.kID)+'")]',
-			aTab,
-			Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
-		).singleNodeValue;
+		let tabs = this.getDescendantTabs(aTab);
+		return tabs.length ? tabs[tabs.length-1] : null ;
 	},
  
 	collectRootTabs : function TSTBase_collectRootTabs(aTabs) /* PUBLIC API */ 
diff --git a/modules/browser.js b/modules/browser.js
index be34f07..afd0948 100644
--- a/modules/browser.js
+++ b/modules/browser.js
@@ -36,9 +36,7 @@
  *
  * ***** END LICENSE BLOCK ******/
  
-const EXPORTED_SYMBOLS = ['TreeStyleTabBrowser']; 
-
-const DEBUG = false;
+var EXPORTED_SYMBOLS = ['TreeStyleTabBrowser']; 
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
@@ -47,6 +45,7 @@ const Cu = Components.utils;
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Timer.jsm');
 Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
+Cu.import('resource://treestyletab-modules/ReferenceCounter.js');
 
 XPCOMUtils.defineLazyModuleGetter(this, 'Services', 'resource://gre/modules/Services.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Promise', 'resource://gre/modules/Promise.jsm');
@@ -135,7 +134,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 	startProp                  : 'top',
 	endProp                    : 'bottom',
 
-	maxTreeLevelPhisical : false,
+	maxTreeLevelPhysical : false,
 
 	needRestoreTree : false,
  
@@ -825,16 +824,26 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		this.initTabbar(null, this.kTABBAR_TOP, true);
 
 		w.addEventListener('resize', this, true);
+		ReferenceCounter.add('w,resize,TSTBrowser,true');
 		w.addEventListener('beforecustomization', this, true);
+		ReferenceCounter.add('w,beforecustomization,TSTBrowser,true');
 		w.addEventListener('aftercustomization', this, false);
+		ReferenceCounter.add('w,aftercustomization,TSTBrowser,false');
 		w.addEventListener('customizationchange', this, false);
+		ReferenceCounter.add('w,customizationchange,TSTBrowser,false');
 		w.addEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
+		ReferenceCounter.add('w,kEVENT_TYPE_PRINT_PREVIEW_ENTERED,TSTBrowser,false');
 		w.addEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED,  this, false);
+		ReferenceCounter.add('w,kEVENT_TYPE_PRINT_PREVIEW_EXITED,TSTBrowser,false');
 		w.addEventListener('tabviewframeinitialized', this, false);
+		ReferenceCounter.add('w,tabviewframeinitialized,TSTBrowser,false');
 		w.addEventListener(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
+		ReferenceCounter.add('w,kEVENT_TYPE_TAB_FOCUS_SWITCHING_END,TSTBrowser,false');
 		w.addEventListener('SSWindowStateBusy', this, false);
+		ReferenceCounter.add('w,SSWindowStateBusy,TSTBrowser,false');
 
 		b.addEventListener('nsDOMMultipleTabHandlerTabsClosing', this, false);
+		ReferenceCounter.add('b,nsDOMMultipleTabHandlerTabsClosing,TSTBrowser,false');
 
 		w['piro.sakura.ne.jp'].tabsDragUtils.initTabBrowser(b);
 
@@ -870,28 +879,6 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		this.fixTooNarrowTabbar();
 
 		this.fireTabbarPositionEvent(false, 'top', position); /* PUBLIC API */
-
-		if (this.timers['init'])
-			clearTimeout(this.timers['init']);
-
-		this.timers['init'] = setTimeout((function() {
-			try {
-				// This command is always enabled and the TabsOnTop can be enabled
-				// by <tabbrowser>.updateVisibility().
-				// So we have to reset TabsOnTop state on the startup.
-				var toggleTabsOnTop = d.getElementById('cmd_ToggleTabsOnTop');
-				var TabsOnTop = 'TabsOnTop' in w ? w.TabsOnTop : null ;
-				if (TabsOnTop && TabsOnTop.syncUI && toggleTabsOnTop && this.isVertical) {
-					toggleTabsOnTop.setAttribute('disabled', true);
-					if (TabsOnTop.enabled && TabsOnTop.toggle)
-						TabsOnTop.toggle();
-				}
-			}
-			catch(e) {
-				this.defaultErrorHandler(e);
-			}
-			delete this.timers['init'];
-		}).bind(this), 0);
 	},
 	
 	_initTabbrowserExtraContents : function TSTBrowser_initTabbrowserExtraContents() 
@@ -934,6 +921,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		var tabContextMenu = b.tabContextMenu ||
 							d.getAnonymousElementByAttribute(b, 'anonid', 'tabContextMenu');
 		tabContextMenu.addEventListener('popupshowing', this, false);
+		ReferenceCounter.add('tabContextMenu,popupshowing,TSTBrowser,false');
 		if (!('MultipleTabService' in w)) {
 			w.setTimeout(function(aSelf, aTabBrowser, aPopup) {
 				let suffix = '-tabbrowser-'+(aTabBrowser.id || 'instance-'+parseInt(Math.random() * 65000));
@@ -1011,7 +999,9 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		var w = this.window;
 		this._DNDObserversInitialized = false;
 		w.addEventListener('mouseover', this, true);
+		ReferenceCounter.add('w,mouseover,TSTBrowser,true');
 		w.addEventListener('dragover', this, true);
+		ReferenceCounter.add('w,dragover,TSTBrowser,true');
 	},
 	
 	_initDNDObservers : function TSTBrowser_initDNDObservers() 
@@ -1024,7 +1014,9 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 
 		var w = this.window;
 		w.removeEventListener('mouseover', this, true);
+		ReferenceCounter.remove('w,mouseover,TSTBrowser,true');
 		w.removeEventListener('dragover', this, true);
+		ReferenceCounter.remove('w,dragover,TSTBrowser,true');
 		this._DNDObserversInitialized = true;
 	},
   
@@ -1633,11 +1625,13 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		return new Promise((function(aResolve, aReject) {
 			var onInitialized = (function() {
 				this.mTabBrowser.removeEventListener(this.kEVENT_TYPE_TABBAR_INITIALIZED, onInitialized, false);
+				ReferenceCounter.remove('mTabBrowser,kEVENT_TYPE_TABBAR_INITIALIZED,onInitialized,false');
 				if (!aIsTemporaryChange)
 					delete this._temporaryPosition;
 				aResolve();
 			}).bind(this);
 			this.mTabBrowser.addEventListener(this.kEVENT_TYPE_TABBAR_INITIALIZED, onInitialized, false);
+			ReferenceCounter.add('mTabBrowser,kEVENT_TYPE_TABBAR_INITIALIZED,onInitialized,false');
 		}).bind(this));
 	},
 	
@@ -1647,27 +1641,46 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 
 		var tabContainer = b.mTabContainer;
 		tabContainer.addEventListener('TabOpen',        this, true);
+		ReferenceCounter.add('tabContainer,TabOpen,TSTBrowser,true');
 		tabContainer.addEventListener('TabClose',       this, true);
+		ReferenceCounter.add('tabContainer,TabClose,TSTBrowser,true');
 		tabContainer.addEventListener('TabMove',        this, true);
+		ReferenceCounter.add('tabContainer,TabMove,TSTBrowser,true');
 		tabContainer.addEventListener('TabShow',        this, true);
+		ReferenceCounter.add('tabContainer,TabShow,TSTBrowser,true');
 		tabContainer.addEventListener('TabHide',        this, true);
+		ReferenceCounter.add('tabContainer,TabHide,TSTBrowser,true');
 		tabContainer.addEventListener('SSTabRestoring', this, true);
+		ReferenceCounter.add('tabContainer,SSTabRestoring,TSTBrowser,true');
 		tabContainer.addEventListener('SSTabRestored',  this, true);
+		ReferenceCounter.add('tabContainer,SSTabRestored,TSTBrowser,true');
 		tabContainer.addEventListener('TabPinned',      this, true);
+		ReferenceCounter.add('tabContainer,TabPinned,TSTBrowser,true');
 		tabContainer.addEventListener('TabUnpinned',    this, true);
+		ReferenceCounter.add('tabContainer,TabUnpinned,TSTBrowser,true');
 		tabContainer.addEventListener('mouseover', this, true);
+		ReferenceCounter.add('tabContainer,mouseover,TSTBrowser,true');
 		tabContainer.addEventListener('mouseout', this, true);
+		ReferenceCounter.add('tabContainer,mouseout,TSTBrowser,true');
 		tabContainer.addEventListener('dblclick',  this, true);
+		ReferenceCounter.add('tabContainer,dblclick,TSTBrowser,true');
 		tabContainer.addEventListener('select', this, true);
+		ReferenceCounter.add('tabContainer,select,TSTBrowser,true');
 		tabContainer.addEventListener('scroll', this, true);
+		ReferenceCounter.add('tabContainer,scroll,TSTBrowser,true');
 
 		var strip = this.tabStrip;
 		strip.addEventListener('MozMouseHittest', this, true); // to block default behaviors of the tab bar
+		ReferenceCounter.add('strip,MozMouseHittest,TSTBrowser,true');
 		strip.addEventListener('mousedown',       this, true);
+		ReferenceCounter.add('strip,mousedown,TSTBrowser,true');
 		strip.addEventListener('click',           this, true);
+		ReferenceCounter.add('strip,click,TSTBrowser,true');
 
 		this.scrollBox.addEventListener('overflow', this, true);
+		ReferenceCounter.add('scrollBox,overflow,TSTBrowser,true');
 		this.scrollBox.addEventListener('underflow', this, true);
+		ReferenceCounter.add('scrollBox,underflow,TSTBrowser,true');
 	},
  
 	_ensureNewSplitter : function TSTBrowser__ensureNewSplitter() 
@@ -1678,13 +1691,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		// We always have to re-create splitter, because its "collapse"
 		// behavior becomes broken by repositioning of the tab bar.
 		if (splitter) {
-			try {
-				splitter.removeEventListener('mousedown', this.windowService, false);
-				splitter.removeEventListener('mouseup', this.windowService, false);
-				splitter.removeEventListener('dblclick', this.windowService, false);
-			}
-			catch(e) {
-			}
+			this._destroyOldSplitter();
 			let oldSplitter = splitter;
 			splitter = oldSplitter.cloneNode(true);
 			oldSplitter.parentNode.removeChild(oldSplitter);
@@ -1713,13 +1720,15 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			// So, we have to turn the actual tab bar visible manually
 			// when the grippy is clicked.
 			let tabContainer = this.mTabBrowser.tabContainer;
-			grippy.addEventListener('click', function() {
+			let grippyOnClick = function() {
 				tabContainer.ownerDocument.defaultView.setTimeout(function() {
 					var visible = grippy.getAttribute('state') != 'collapsed';
 					if (visible != tabContainer.visible)
 						tabContainer.visible = visible;
 				}, 0);
-			}, true);
+			};
+			grippy.addEventListener('click', grippy.grippyOnClick, true);
+			ReferenceCounter.add('grippy,click,grippy.grippyOnClick,true');
 			splitter.appendChild(grippy);
 		}
 
@@ -1729,15 +1738,39 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		splitter.setAttribute('class', splitterClass);
 
 		splitter.addEventListener('mousedown', this.windowService, false);
+		ReferenceCounter.add('splitter,mousedown,windowService,false');
 		splitter.addEventListener('mouseup', this.windowService, false);
+		ReferenceCounter.add('splitter,mouseup,windowService,false');
 		splitter.addEventListener('dblclick', this.windowService, false);
+		ReferenceCounter.add('splitter,dblclick,windowService,false');
 
 		var ref = this.mTabBrowser.mPanelContainer;
 		ref.parentNode.insertBefore(splitter, ref);
 
+		this.splitter = splitter;
 		return splitter;
 	},
  
+	_destroyOldSplitter : function TSTBrowser_destroyOldSplitter(aChanging, aOldPosition, aNewPosition) 
+	{
+		var d = this.document;
+		var splitter = this.splitter;
+		try {
+			splitter.removeEventListener('mousedown', this.windowService, false);
+			ReferenceCounter.remove('splitter,mousedown,windowService,false');
+			splitter.removeEventListener('mouseup', this.windowService, false);
+			ReferenceCounter.remove('splitter,mouseup,windowService,false');
+			splitter.removeEventListener('dblclick', this.windowService, false);
+			ReferenceCounter.remove('splitter,dblclick,windowService,false');
+			var grippy = splitter.firstChild;
+			grippy.removeEventListener('click', grippy.grippyOnClick, true);
+			ReferenceCounter.remove('grippy,click,grippy.grippyOnClick,true');
+			delete grippy.grippyOnClick;
+		}
+		catch(e) {
+		}
+	},
+ 
 	fireTabbarPositionEvent : function TSTBrowser_fireTabbarPositionEvent(aChanging, aOldPosition, aNewPosition) 
 	{
 		if (aOldPosition == aNewPosition)
@@ -1766,13 +1799,9 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		var d = this.document;
 		var b = this.mTabBrowser;
 		var orient;
-		var toggleTabsOnTop = d.getElementById('cmd_ToggleTabsOnTop');
-		var TabsOnTop = 'TabsOnTop' in w ? w.TabsOnTop : null ;
 		if (this.isVertical) {
 			orient = 'vertical';
 			this.fixed = this.fixed; // ensure set to the current orient
-			if (toggleTabsOnTop)
-				toggleTabsOnTop.setAttribute('disabled', true);
 		}
 		else {
 			orient = 'horizontal';
@@ -1785,57 +1814,12 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 				// remove ordinal for "tabs on top" https://bugzilla.mozilla.org/show_bug.cgi?id=544815
 				if (this.position == 'top') {
 					this.removeTabStripAttribute('ordinal');
-					if (TabsOnTop && !this.windowService.isPopupWindow &&
-						this.windowService.initialized) {
-						let currentState = TabsOnTop.enabled;
-						let originalState = utils.getTreePref('tabsOnTop.originalState');
-						if (originalState !== null &&
-							currentState != originalState &&
-							this.windowService.tabsOnTopChangingByUI &&
-							!this.windowService.changingTabsOnTop)
-							utils.setTreePref('tabsOnTop.originalState', currentState);
-						// Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=555987
-						// This should be done when the value of the "ordinal" attribute
-						// is modified dynamically. So, we don' have to do it before
-						// the browser window is completely initialized.
-						TabsOnTop.enabled = !currentState;
-						if (this.timers['updateTabbarState_TabsOnTop'])
-							clearTimeout(this.timers['updateTabbarState_TabsOnTop']);
-						this.timers['updateTabbarState_TabsOnTop'] = setTimeout((function() {
-							try {
-								TabsOnTop.enabled = currentState;
-							}
-							catch(e) {
-								this.defaultErrorHandler(e);
-							}
-							delete this.timers['updateTabbarState_TabsOnTop'];
-						}).bind(this), 0);
-					}
 				}
 			}
 			else {
 				this.fixed = false; // ensure set to the current orient
 				this.setTabStripAttribute('height', this.maxTabbarHeight(this.tabbarHeight, b));
 			}
-			if (toggleTabsOnTop) {
-				if (this.position == 'top')
-					toggleTabsOnTop.removeAttribute('disabled');
-				else
-					toggleTabsOnTop.setAttribute('disabled', true);
-			}
-		}
-
-		if (TabsOnTop && !this.windowService.isPopupWindow) {
-			let updateTabsOnTop = (function() {
-					this.windowService.updateTabsOnTop();
-				}).bind(this);
-			// TabsOnTop.enabled is always "false" before the browser window is
-			// completely initialized. So, we have to check it with delay only
-			// on the Startup.
-			if (this.initialized)
-				updateTabsOnTop();
-			else
-				setTimeout(updateTabsOnTop, 0);
 		}
 
 		if (this.timers['updateTabbarState'])
@@ -1861,7 +1845,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		this.setTabbrowserAttribute(this.kALLOW_STACK, this.canStackTabs ? 'true' : null);
 		this.updateTabsZIndex(this.canStackTabs);
 
-		if (this.maxTreeLevelPhisical)
+		if (this.maxTreeLevelPhysical)
 			this.promoteTooDeepLevelTabs();
 
 		this.updateAllTabsIndent();
@@ -1952,7 +1936,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 	{
 		aReason = aReason || this.kTABBAR_UPDATE_BY_UNKNOWN_REASON;
 
-		if (DEBUG) {
+		if (utils.isDebugging('browser')) {
 			let humanReadableReason =
 				(aReason & this.kTABBAR_UPDATE_BY_RESET ? 'reset ' : '' ) +
 				(aReason & this.kTABBAR_UPDATE_BY_PREF_CHANGE ? 'prefchange ' : '' ) +
@@ -2088,11 +2072,19 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		else
 			this.positionPinnedTabsWithDelay(null, null, aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE);
 
-		if (!collapsed && aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE)
-			setTimeout((function() {
-				if (this.browser) // ignore calling after destroyed...
-					this.scrollToTab(this.browser.selectedTab);
-			}).bind(this), 0);
+		this.notifyingRenderedEvent = true;
+		var event = d.createEvent('Events');
+		event.initEvent(this.kEVENT_TYPE_TABBAR_RENDERED, true, false);
+		this.mTabBrowser.tabContainer.dispatchEvent(event);
+
+		setTimeout((function() {
+			this.notifyingRenderedEvent = false;
+
+			if (!collapsed &&
+				aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE &&
+				this.browser) // ignore calling after destroyed...
+				this.scrollToTab(this.browser.selectedTab);
+		}).bind(this), 0);
 	},
 	getTabbarPlaceholderSize: function TSTBrowser_getTabbarPlaceholderSize()
 	{
@@ -2274,9 +2266,6 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			delete this.timers[key];
 		}, this);
 
-		this.autoHide.destroy();
-		delete this._autoHide;
-
 		this._initDNDObservers(); // ensure initialized
 		this.tabbarDNDObserver.destroy();
 		delete this._tabbarDNDObserver;
@@ -2293,6 +2282,8 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			delete this.tabStripPlaceHolderBoxObserver;
 		}
 
+		this._destroyOldSplitter();
+
 		var w = this.window;
 		var d = this.document;
 		var b = this.mTabBrowser;
@@ -2309,23 +2300,37 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 
 		this._endListenTabbarEvents();
 
+		this.autoHide.destroy();
+		this._autoHide = undefined; // block to be re-initialized by property accesses
+
 		w.removeEventListener('resize', this, true);
+		ReferenceCounter.remove('w,resize,TSTBrowser,true');
 		w.removeEventListener('beforecustomization', this, true);
+		ReferenceCounter.remove('w,beforecustomization,TSTBrowser,true');
 		w.removeEventListener('aftercustomization', this, false);
+		ReferenceCounter.remove('w,aftercustomization,TSTBrowser,false');
 		w.removeEventListener('customizationchange', this, false);
+		ReferenceCounter.remove('w,customizationchange,TSTBrowser,false');
 		w.removeEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_ENTERED, this, false);
+		ReferenceCounter.remove('w,kEVENT_TYPE_PRINT_PREVIEW_ENTERED,TSTBrowser,false');
 		w.removeEventListener(this.kEVENT_TYPE_PRINT_PREVIEW_EXITED,  this, false);
+		ReferenceCounter.remove('w,kEVENT_TYPE_PRINT_PREVIEW_EXITED,TSTBrowser,false');
 		w.removeEventListener('tabviewframeinitialized', this, false);
+		ReferenceCounter.remove('w,tabviewframeinitialized,TSTBrowser,false');
 		w.removeEventListener(this.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
+		ReferenceCounter.remove('w,kEVENT_TYPE_TAB_FOCUS_SWITCHING_END,TSTBrowser,false');
 		w.removeEventListener('SSWindowStateBusy', this, false);
+		ReferenceCounter.remove('w,SSWindowStateBusy,TSTBrowser,false');
 
 		b.removeEventListener('nsDOMMultipleTabHandlerTabsClosing', this, false);
+		ReferenceCounter.remove('b,nsDOMMultipleTabHandlerTabsClosing,TSTBrowser,false');
 
 		w['piro.sakura.ne.jp'].tabsDragUtils.destroyTabBrowser(b);
 
 		var tabContextMenu = b.tabContextMenu ||
 							d.getAnonymousElementByAttribute(b, 'anonid', 'tabContextMenu');
 		tabContextMenu.removeEventListener('popupshowing', this, false);
+		ReferenceCounter.remove('tabContextMenu,popupshowing,TSTBrowser,false');
 
 		if (this.tabbarCanvas) {
 			this.tabbarCanvas.parentNode.removeChild(this.tabbarCanvas);
@@ -2354,7 +2359,9 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 
 		if (aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave) {
 			this.document.removeEventListener('mouseover', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+			ReferenceCounter.remove('document,mouseover,aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave,true');
 			this.document.removeEventListener('mouseout', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+			ReferenceCounter.remove('document,mouseout,aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave,true');
 			delete aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave;
 		}
 
@@ -2372,27 +2379,46 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 
 		var tabContainer = b.mTabContainer;
 		tabContainer.removeEventListener('TabOpen',        this, true);
+		ReferenceCounter.remove('tabContainer,TabOpen,TSTBrowser,true');
 		tabContainer.removeEventListener('TabClose',       this, true);
+		ReferenceCounter.remove('tabContainer,TabClose,TSTBrowser,true');
 		tabContainer.removeEventListener('TabMove',        this, true);
+		ReferenceCounter.remove('tabContainer,TabMove,TSTBrowser,true');
 		tabContainer.removeEventListener('TabShow',        this, true);
+		ReferenceCounter.remove('tabContainer,TabShow,TSTBrowser,true');
 		tabContainer.removeEventListener('TabHide',        this, true);
+		ReferenceCounter.remove('tabContainer,TabHide,TSTBrowser,true');
 		tabContainer.removeEventListener('SSTabRestoring', this, true);
+		ReferenceCounter.remove('tabContainer,SSTabRestoring,TSTBrowser,true');
 		tabContainer.removeEventListener('SSTabRestored',  this, true);
+		ReferenceCounter.remove('tabContainer,SSTabRestored,TSTBrowser,true');
 		tabContainer.removeEventListener('TabPinned',      this, true);
+		ReferenceCounter.remove('tabContainer,TabPinned,TSTBrowser,true');
 		tabContainer.removeEventListener('TabUnpinned',    this, true);
+		ReferenceCounter.remove('tabContainer,TabUnpinned,TSTBrowser,true');
 		tabContainer.removeEventListener('mouseover', this, true);
+		ReferenceCounter.remove('tabContainer,mouseover,TSTBrowser,true');
 		tabContainer.removeEventListener('mouseout', this, true);
+		ReferenceCounter.remove('tabContainer,mouseout,TSTBrowser,true');
 		tabContainer.removeEventListener('dblclick',  this, true);
+		ReferenceCounter.remove('tabContainer,dblclick,TSTBrowser,true');
 		tabContainer.removeEventListener('select', this, true);
+		ReferenceCounter.remove('tabContainer,select,TSTBrowser,true');
 		tabContainer.removeEventListener('scroll', this, true);
+		ReferenceCounter.remove('tabContainer,scroll,TSTBrowser,true');
 
 		var strip = this.tabStrip;
 		strip.removeEventListener('MozMouseHittest', this, true);
+		ReferenceCounter.remove('strip,MozMouseHittest,TSTBrowser,true');
 		strip.removeEventListener('mousedown',       this, true);
+		ReferenceCounter.remove('strip,mousedown,TSTBrowser,true');
 		strip.removeEventListener('click',           this, true);
+		ReferenceCounter.remove('strip,click,TSTBrowser,true');
 
 		this.scrollBox.removeEventListener('overflow', this, true);
+		ReferenceCounter.remove('scrollBox,overflow,TSTBrowser,true');
 		this.scrollBox.removeEventListener('underflow', this, true);
+		ReferenceCounter.remove('scrollBox,underflow,TSTBrowser,true');
 	},
  
 	saveCurrentState : function TSTBrowser_saveCurrentState() 
@@ -2428,9 +2454,11 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			return new Promise((function(aResolve, aReject) {
 				var onRestored = (function() {
 					this.mTabBrowser.removeEventListener(this.kEVENT_TYPE_TABBAR_POSITION_CHANGED, onRestored, false);
+					ReferenceCounter.remove('mTabBrowser,kEVENT_TYPE_TABBAR_POSITION_CHANGED,onRestored,false');
 					aResolve();
 				}).bind(this);
 				this.mTabBrowser.addEventListener(this.kEVENT_TYPE_TABBAR_POSITION_CHANGED, onRestored, false);
+				ReferenceCounter.add('mTabBrowser,kEVENT_TYPE_TABBAR_POSITION_CHANGED,onRestored,false');
 			}).bind(this))
 				.then(this.destroyTabbarPostProcess.bind(this));
 		}
@@ -2533,8 +2561,10 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		if (aPopup.state == 'open') {
 			aPopup.addEventListener('popuphidden', function onPopuphidden(aEvent) {
 				aPopup.removeEventListener(aEvent.type, onPopuphidden, false);
+				ReferenceCounter.remove('aPopup,popuphidden,onPopuphidden,false');
 				aPopup.parentNode.removeChild(aPopup);
 			}, false);
+			ReferenceCounter.add('aPopup,popuphidden,onPopuphidden,false');
 			aPopup.hidePopup();
 		}
 		else {
@@ -2702,8 +2732,8 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			case 'extensions.treestyletab.tabbar.narrowScrollbar':
 				return this.setTabbrowserAttribute(this.kNARROW_SCROLLBAR, value);
 
-			case 'extensions.treestyletab.maxTreeLevel.phisical':
-				if (this.maxTreeLevelPhisical = value)
+			case 'extensions.treestyletab.maxTreeLevel.physical':
+				if (this.maxTreeLevelPhysical = value)
 					this.promoteTooDeepLevelTabs();
 				return;
 
@@ -3047,6 +3077,15 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		var pareintIndexInTree = hasStructure ? this.treeStructure.shift() : 0 ;
 		var lastRelatedTab = b._lastRelatedTab;
 
+		if (utils.isDebugging('browser')) {
+			dump('TSTBrowser_onTabOpen\n  ' + [
+			  'readiedToAttachNewTab: '+this.readiedToAttachNewTab,
+			  'parentTab: '+this.parentTab + ' (' + this.getTabById(this.parentTab) + ')',
+			  'insertBefore: '+this.insertBefore,
+			  'treeStructure: '+this.treeStructure
+			].join('\n  ') + '\n');
+		}
+
 		if (this.readiedToAttachNewTab) {
 			if (pareintIndexInTree < 0) { // there is no parent, so this is a new parent!
 				this.parentTab = tab.getAttribute(this.kID);
@@ -3167,19 +3206,50 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
  
 	updateInsertionPositionInfo : function TSTBrowser_updateInsertionPositionInfo(aTab) 
 	{
-		if (!aTab.parentNode) // do nothing for closed tab!
+		if (!aTab ||
+			!aTab.parentNode) // do nothing for closed tab!
 			return;
 
 		var prev = this.getPreviousSiblingTab(aTab);
 		if (prev) {
 			this.setTabValue(aTab, this.kINSERT_AFTER, prev.getAttribute(this.kID));
 			this.setTabValue(prev, this.kINSERT_BEFORE, aTab.getAttribute(this.kID));
+		} else {
+			this.deleteTabValue(aTab, this.kINSERT_AFTER);
 		}
 
 		var next = this.getNextSiblingTab(aTab);
 		if (next) {
 			this.setTabValue(aTab, this.kINSERT_BEFORE, next.getAttribute(this.kID));
 			this.setTabValue(next, this.kINSERT_AFTER, aTab.getAttribute(this.kID));
+		} else {
+			this.deleteTabValue(aTab, this.kINSERT_BEFORE);
+		}
+	},
+ 
+	closeUpInsertionPositionInfoAround : function TSTBrowser_closeUpInsertionPositionInfoAround(aTab) 
+	{
+		if (!aTab ||
+			!aTab.parentNode) // do nothing for closed tab!
+			return;
+
+		var prev = this.getPreviousSiblingTab(aTab);
+		var next = this.getNextSiblingTab(aTab);
+		if (prev) {
+			this.setTabValue(aTab, this.kINSERT_AFTER, prev.getAttribute(this.kID));
+
+			if (next)
+				this.setTabValue(prev, this.kINSERT_BEFORE, next.getAttribute(this.kID));
+			else
+				this.deleteTabValue(prev, this.kINSERT_BEFORE);
+		}
+		if (next) {
+			this.setTabValue(aTab, this.kINSERT_BEFORE, next.getAttribute(this.kID));
+
+			if (prev)
+				this.setTabValue(next, this.kINSERT_AFTER, prev.getAttribute(this.kID));
+			else
+				this.deleteTabValue(next, this.kINSERT_AFTER);
 		}
 	},
   
@@ -3197,15 +3267,13 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		var closeParentBehavior = this.getCloseParentBehaviorForTab(tab);
 
 		var backupAttributes = this._collectBackupAttributes(tab);
-		if (DEBUG)
+		if (utils.isDebugging('browser'))
 			dump('onTabClose: backupAttributes = '+JSON.stringify(backupAttributes)+'\n');
 
 		if (closeParentBehavior == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN ||
 			this.isSubtreeCollapsed(tab))
 			this._closeChildTabs(tab);
 
-		this._saveAndUpdateReferenceTabsInfo(tab);
-
 		var firstChild = this.getFirstChildTab(tab);
 
 		this.detachAllChildren(tab, {
@@ -3357,28 +3425,6 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		}).bind(this), 0);
 	},
  
-	_saveAndUpdateReferenceTabsInfo : function TSTBrowser_saveAndUpdateReferenceTabsInfo(aTab) 
-	{
-		var prev = this.getPreviousSiblingTab(aTab);
-		var next = this.getNextSiblingTab(aTab);
-		if (prev) {
-			this.setTabValue(aTab, this.kINSERT_AFTER, prev.getAttribute(this.kID));
-
-			if (next)
-				this.setTabValue(prev, this.kINSERT_BEFORE, next.getAttribute(this.kID));
-			else
-				this.deleteTabValue(prev, this.kINSERT_BEFORE);
-		}
-		if (next) {
-			this.setTabValue(aTab, this.kINSERT_BEFORE, next.getAttribute(this.kID));
-
-			if (prev)
-				this.setTabValue(next, this.kINSERT_AFTER, prev.getAttribute(this.kID));
-			else
-				this.deleteTabValue(next, this.kINSERT_AFTER);
-		}
-	},
- 
 	_restoreTabAttributes : function TSTBrowser_restoreTabAttributes(aTab, aAttributes) 
 	{
 		for (var i in aAttributes)
@@ -3473,52 +3519,29 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			this.moveTabSubtreeTo(tab, tab._tPos);
 		}
 
-		var parentTab = this.getParentTab(tab);
-		if (parentTab && !this.subTreeChildrenMovingCount) {
-			this.updateChildrenArray(parentTab);
-		}
-
 		this.updateTabsCount(tab, true);
 
-		var prev = this.getPreviousSiblingTab(tab);
-		var next = this.getNextSiblingTab(tab);
-
-		if (prev) {
-			this.setTabValue(prev, this.kINSERT_BEFORE, tab.getAttribute(this.kID));
-			this.setTabValue(tab, this.kINSERT_AFTER, prev.getAttribute(this.kID));
-		}
-		else
-			this.deleteTabValue(tab, this.kINSERT_AFTER);
-
-		if (next) {
-			this.setTabValue(next, this.kINSERT_AFTER, tab.getAttribute(this.kID));
-			this.setTabValue(tab, this.kINSERT_BEFORE, next.getAttribute(this.kID));
-		}
-		else
-			this.deleteTabValue(tab, this.kINSERT_BEFORE);
-
-		var old = aEvent.detail;
-		if (old > tab._tPos)
-			old--;
-		var tabs = this.getAllTabs(b);
-		old = tabs[old];
-
-		prev = this.getPreviousSiblingTab(old);
-		next = this.getNextSiblingTab(old);
+		var tabsToBeUpdated = [tab];
 
-		if (prev) {
-			this.setTabValue(prev, this.kINSERT_BEFORE, old.getAttribute(this.kID));
-			this.setTabValue(old, this.kINSERT_AFTER, prev.getAttribute(this.kID));
+		var parentTab = this.getParentTab(tab);
+		if (parentTab) {
+			let children = this.getChildTabs(parentTab);
+			let oldChildIndex = children.indexOf(tab);
+			if (oldChildIndex > -1) {
+				if (oldChildIndex > 0) {
+					let oldPrevTab = children[oldChildIndex - 1];
+					tabsToBeUpdated.push(oldPrevTab);
+				}
+				if (oldChildIndex < children.lenght - 1) {
+					let oldNextTab = children[oldChildIndex + 1];
+					tabsToBeUpdated.push(oldNextTab);
+				}
+			}
+			if (!this.subTreeChildrenMovingCount)
+				this.updateChildrenArray(parentTab);
 		}
-		else
-			this.deleteTabValue(old, this.kINSERT_AFTER);
 
-		if (next) {
-			this.setTabValue(next, this.kINSERT_AFTER, old.getAttribute(this.kID));
-			this.setTabValue(old, this.kINSERT_BEFORE, next.getAttribute(this.kID));
-		}
-		else
-			this.deleteTabValue(old, this.kINSERT_BEFORE);
+		tabsToBeUpdated.forEach(this.updateInsertionPositionInfo, this);
 
 		this.positionPinnedTabsWithDelay();
 
@@ -3560,6 +3583,11 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			delta = Math.abs(pos - oldPos);
 		}
 
+		if (utils.isDebugging('browser')) {
+			dump('attachTabFromPosition '+aTab._tPos+' / '+aOldPosition+'\n');
+			dump((new Error()).stack.replace(/^/gm, '  ')+'\n');
+		}
+
 		var prevTab = this.getPreviousTab(aTab);
 		var nextTab = this.getNextTab(aTab);
 
@@ -3909,7 +3937,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 	handleRestoredTab : function TSTBrowser_handleRestoredTab(aTab) 
 	{
 		if (aTab.__treestyletab__restoreState === undefined) {
-			if (DEBUG)
+			if (utils.isDebugging('browser'))
 				dump('handleRestoredTab: ' + aTab._tPos + ' is already restored!\n');
 			return false;
 		}
@@ -4138,7 +4166,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		var restoringMultipleTabs = this.windowService.restoringTree;
 		var position = this._prepareInsertionPosition(aTab, aMayBeDuplicated);
 		var parent = position.parent;
-		if (DEBUG)
+		if (utils.isDebugging('browser'))
 			dump('handleRestoredTab: found parent = ' + parent+'\n');
 		if (parent) {
 			aTab.removeAttribute(this.kPARENT);
@@ -4185,7 +4213,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		}
 
 		var ancestors = (this.getTabValue(aTab, this.kANCESTORS) || this.getTabValue(aTab, this.kPARENT)).split('|');
-		if (DEBUG)
+		if (utils.isDebugging('browser'))
 			dump('handleRestoredTab: ancestors = ' + ancestors+'\n');
 		var parent = null;
 		for (let i in ancestors)
@@ -4208,7 +4236,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		 */
 		if (!parent) {
 			parent = aTab.getAttribute(this.kPARENT);
-			if (DEBUG)
+			if (utils.isDebugging('browser'))
 				dump('handleRestoredTab: parent = ' + parent+'\n');
 			if (parent && !next)
 				next = this.getNextSiblingTab(aTab);
@@ -4421,6 +4449,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			let self = this;
 			aRestoredTab.addEventListener('SSTabRestoring', function onSSTabRestoring(aEvent) {
 				aRestoredTab.removeEventListener(aEvent.type, onSSTabRestoring, false);
+				ReferenceCounter.remove('aRestoredTab,SSTabRestoring,onSSTabRestoring,false');
 				self.askUndoCloseTabSetBehavior(aRestoredTab, indexes.length)
 					.then(function(aBehavior) {
 						if (aBehavior & self.kUNDO_CLOSE_SET)
@@ -4430,6 +4459,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 						Components.utils.reportError(aError);
 					});
 			}, false);
+			ReferenceCounter.add('aRestoredTab,SSTabRestoring,onSSTabRestoring,false');
 		}
 		else if (behavior & this.kUNDO_CLOSE_SET) {
 			this.doRestoreClosedSet(aRestoredTab, indexes);
@@ -4947,6 +4977,11 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		}
 
 		if (isContentResize || isChromeResize) {
+			if (utils.isDebugging('browser')) {
+				dump('TSTBrowser_onResize\n');
+				dump('  isContentResize = '+isContentResize+'\n');
+				dump('  isChromeResize = '+isChromeResize+'\n');
+			}
 			this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
 			this.updateInvertedTabContentsOrder(true);
 			this.mTabBrowser.mTabContainer.adjustTabstrip();
@@ -5106,52 +5141,15 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		}
 	},
   
-	onTabsOnTopSyncCommand : function TSTBrowser_onTabsOnTopSyncCommand(aEnabled) 
-	{
-		if (
-			this.windowService.tabsOnTopChangingByUI ||
-			!aEnabled ||
-			this.position != 'top' ||
-			this.fixed ||
-			this.windowService.isPopupWindow
-			)
-			return;
-		this.windowService.tabsOnTopChangingByUI = true;
-		if (this.timers['onTabsOnTopSyncCommand'])
-			clearTimeout(this.timers['onTabsOnTopSyncCommand']);
-		this.timers['onTabsOnTopSyncCommand'] = setTimeout((function() {
-			Deferred.resolve()
-				.then((function() {
-					this.windowService.toggleFixed(this.mTabBrowser);
-					return wait(0);
-				}).bind(this))
-				.then((function() {
-					if (this.window.TabsOnTop.enabled != aEnabled)
-						this.window.TabsOnTop.enabled = aEnabled;
-				}).bind(this))
-				.catch(this.defaultErrorHandler.bind(this))
-				.then((function() {
-					this.windowService.tabsOnTopChangingByUI = false;
-					delete this.timers['onTabsOnTopSyncCommand'];
-				}).bind(this));
-		}).bind(this), 0);
-	},
- 
 	onBeforeFullScreenToggle : function TSTBrowser_onBeforeFullScreenToggle(aEnterFS)
 	{
 		if (this.position != 'top') {
-			// entering to the DOM-fullscreen (ex. YouTube Player)
-			if (this.document.mozFullScreen) {
-				this.setTabbrowserAttribute(this.kDOM_FULLSCREEN_ACTIVATED, true);
-			}
-			else {
-				if (this.document.documentElement.getAttribute(this.kDOM_FULLSCREEN_ACTIVATED) != 'true') {
-					if (aEnterFS)
-						this.autoHide.startForFullScreen();
-					else
-						this.autoHide.endForFullScreen();
-				}
-				this.removeTabbrowserAttribute(this.kDOM_FULLSCREEN_ACTIVATED);
+			// ignore entering to the DOM-fullscreen (ex. YouTube Player)
+			if (!this.document.mozFullScreen) {
+				if (aEnterFS)
+					this.autoHide.startForFullScreen();
+				else
+					this.autoHide.endForFullScreen();
 			}
 		}
 	},
@@ -5292,7 +5290,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 
 		if (aParent) {
 			newAncestors = [aParent].concat(this.getAncestorTabs(aParent));
-			if (this.maxTreeLevelPhisical && this.maxTreeLevel > -1) {
+			if (this.maxTreeLevelPhysical && this.maxTreeLevel > -1) {
 				let level = parseInt(aParent.getAttribute(this.kNEST) || 0) + 1;
 				newAncestors.some(function(aAncestor) {
 					if (level <= this.maxTreeLevel)
@@ -5467,6 +5465,9 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		if (!parentTab)
 			return;
 
+		if (!aInfo.dontUpdateInsertionPositionInfo)
+			this.closeUpInsertionPositionInfoAround(aChild);
+
 		var id = aChild.getAttribute(this.kID);
 
 		this.setTabValue(
@@ -5527,6 +5528,8 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN)
 			aInfo.behavior = this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_FIRST_CHILD;
 
+		aInfo.dontUpdateInsertionPositionInfo = true;
+
 		var b = this.mTabBrowser;
 		var parentTab = this.getParentTab(aTab);
 
@@ -5926,7 +5929,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
  
 	promoteTooDeepLevelTabs : function TSTBrowser_promoteTooDeepLevelTabs(aParent) 
 	{
-		if (this.maxTreeLevel < 0 || !this.maxTreeLevelPhisical)
+		if (this.maxTreeLevel < 0 || !this.maxTreeLevelPhysical)
 			return;
 
 		var tabs = aParent ? this.getDescendantTabs(aParent) : this.getAllTabs(this.mTabBrowser) ;
@@ -6258,12 +6261,16 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 					if (x > rect.left && x < rect.right && y > rect.top && y < rect.bottom)
 						return;
 					self.document.removeEventListener('mouseover', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+					ReferenceCounter.remove('document,mouseover,aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave,true');
 					self.document.removeEventListener('mouseout', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+					ReferenceCounter.remove('document,mouseout,aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave,true');
 					delete aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave;
 					self.checkTabsIndentOverflow();
 				};
 				this.document.addEventListener('mouseover', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+				ReferenceCounter.add('document,mouseover,aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave,true');
 				this.document.addEventListener('mouseout', aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave, true);
+				ReferenceCounter.add('document,mouseout,aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave,true');
 			}
 		}
 	},
@@ -6873,9 +6880,12 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			Components.utils.reportError(new Error('There is no property named "_browserEpochs"!!'));
 		}
 
-		dump('TSTBrowser::restoreTree\n');
-		dump('  level = '+level+'\n');
-		dump('  tabsToRestore = '+tabsToRestore+'\n');
+		if (utils.isDebugging('browser')) {
+			dump('TSTBrowser::restoreTree\n');
+			dump('  level = '+level+'\n');
+			dump('  tabsToRestore = '+tabsToRestore+'\n');
+		}
+
 		if (
 			level <= this.kRESTORE_TREE_LEVEL_NONE ||
 			tabsToRestore <= 1
@@ -6896,7 +6906,10 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 				(!onlyVisible || !aTab.hidden)
 			);
 		});
-		dump('  restoring member tabs = '+tabs.length+' ('+tabs.map(function(aTab) { return aTab._tPos; })+')\n');
+
+		if (utils.isDebugging('browser'))
+			dump('  restoring member tabs = '+tabs.length+' ('+tabs.map(function(aTab) { return aTab._tPos; })+')\n');
+
 		if (tabs.length <= 1)
 			return;
 
@@ -6994,8 +7007,8 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 	isPopupShown : function TSTBrowser_isPopupShown(...aArgs) {
 		return this._callWindowServiceMethod('isPopupShown', aArgs);
 	},
-	updateTabsOnTop : function TSTBrowser_updateTabsOnTop(...aArgs) {
-		return this._callWindowServiceMethod('updateTabsOnTop', aArgs);
+	updateTabsInTitlebar : function TSTBrowser_updateTabsInTitlebar(...aArgs) {
+		return this._callWindowServiceMethod('updateTabsInTitlebar', aArgs);
 	},
 	registerTabFocusAllowance : function TSTBrowser_registerTabFocusAllowance(...aArgs) {
 		return this._callWindowServiceMethod('registerTabFocusAllowance', aArgs);
@@ -7010,7 +7023,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 /* show/hide tab bar */ 
 	get autoHide()
 	{
-		if (!this._autoHide) {
+		if (!('_autoHide' in this)) {
 			this._autoHide = new AutoHideBrowser(this.mTabBrowser);
 		}
 		return this._autoHide;
@@ -7063,7 +7076,38 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 	cancelShowHideTabbarOnMousemove : function TSTBrowser_cancelShowHideTabbarOnMousemove() { this.autoHide.cancelShowHideOnMousemove(); },
 	showTabbarForFeedback : function TSTBrowser_showTabbarForFeedback() { this.autoHide.showForFeedback(); },
 	delayedShowTabbarForFeedback : function TSTBrowser_delayedShowTabbarForFeedback() { this.autoHide.delayedShowForFeedback(); },
-	cancelHideTabbarForFeedback : function TSTBrowser_cancelHideTabbarForFeedback() { this.autoHide.cancelHideForFeedback(); }
+	cancelHideTabbarForFeedback : function TSTBrowser_cancelHideTabbarForFeedback() { this.autoHide.cancelHideForFeedback(); },
   
+	// DEBUGGING
+	dumpTreeInformation : function() {
+		var ids = [];
+		var extraAttributes = {
+			children: this.kCHILDREN,
+			restoringChildren: this.kCHILDREN_RESTORING,
+			parent: this.kPARENT,
+			insertBefore: this.kINSERT_BEFORE,
+			insertAfter: this.kINSERT_AFTER
+		};
+		var result = this.rootTabs.map(function scanTab(aTab) {
+			var id = this.getTabValue(aTab, this.kID);
+			ids.push(id);
+			var result = { id: id };
+			Object.keys(extraAttributes).forEach(function(aKey) {
+				var value = this.getTabValue(aTab, extraAttributes[aKey]);
+				if (value)
+					result[aKey] = value;
+			}, this);
+			var children = this.getChildTabs(aTab).map(scanTab, this);
+			if (children.length > 0)
+				result.actualChildren = children;
+			return result;
+		}, this);
+		var json = JSON.stringify(result);
+		ids.forEach(function(aId, aIndex) {
+			json = json.replace(new RegExp(aId, 'g'), 'TAB-' + aIndex);
+		});
+		return JSON.parse(json);
+	}
+ 
 }); 
  
diff --git a/modules/browserUIShowHideObserver.js b/modules/browserUIShowHideObserver.js
index df1bae0..ac5b391 100644
--- a/modules/browserUIShowHideObserver.js
+++ b/modules/browserUIShowHideObserver.js
@@ -34,16 +34,18 @@
  *
  * ***** END LICENSE BLOCK ******/
 
-const EXPORTED_SYMBOLS = ['BrowserUIShowHideObserver']; 
+var EXPORTED_SYMBOLS = ['BrowserUIShowHideObserver']; 
 
-var DEBUG = false;
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
 
 Components.utils.import('resource://treestyletab-modules/constants.js');
 
-function BrowserUIShowHideObserver(aOwner, aBox) {
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+
+function BrowserUIShowHideObserver(aOwner, aBox, aOptions) {
 	this.owner = aOwner;
 	this.box = aBox;
-	this.init();
+	this.init(aOptions);
 }
 BrowserUIShowHideObserver.prototype = {
 	get MutationObserver()
@@ -52,18 +54,18 @@ BrowserUIShowHideObserver.prototype = {
 		return w.MutationObserver || w.MozMutationObserver;
 	},
 
-	init : function BrowserUIShowHideObserver_onInit() 
+	init : function BrowserUIShowHideObserver_onInit(aOptions) 
 	{
 		if (!this.MutationObserver)
 			return;
 		this.observer = new this.MutationObserver((function(aMutations, aObserver) {
 			this.onMutation(aMutations, aObserver);
 		}).bind(this));
-		this.observer.observe(this.box, {
+		var options = {
 			childList       : true,
 			attributes      : true,
 			subtree         : true,
-			attributeOldValue: DEBUG,
+			attributeOldValue: utils.isDebugging('browserUIShowHideObserver'),
 			attributeFilter : [
 				'hidden',
 				'collapsed',
@@ -72,21 +74,36 @@ BrowserUIShowHideObserver.prototype = {
 				'width',
 				'height'
 			]
-		});
+		};
+		if (aOptions) {
+			Object.keys(options).forEach(function(aKey) {
+				if (aKey in aOptions)
+					options[aKey] = aOptions[aKey];
+			});
+		}
+		this.observer.observe(this.box, options);
 	},
 	onMutation : function BrowserUIShowHideObserver_onMutation(aMutations, aObserver) 
 	{
 		aMutations.forEach(function(aMutation) {
-			switch (aMutation.type)
-			{
-				case 'childList':
-					if (aMutation.target == this.box)
-						this.owner.browser.treeStyleTab.updateFloatingTabbar(TreeStyleTabConstants.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
-					return;
-
-				case 'attributes':
-					this.onAttributeModified(aMutation, aObserver);
-					return;
+			try {
+				switch (aMutation.type)
+				{
+					case 'childList':
+						if (aMutation.target == this.box) {
+							this.dumpMutation(aMutation, 'BrowserUIShowHideObserver_onMutation/childList');
+							this.owner.browser.treeStyleTab.updateFloatingTabbar(TreeStyleTabConstants.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
+						}
+						return;
+
+					case 'attributes':
+						this.onAttributeModified(aMutation, aObserver);
+						return;
+				}
+			}
+			catch(error) {
+				this.dumpMutation(aMutation, 'BrowserUIShowHideObserver_onMutation(error)');
+				Components.utils.reportError(error);
 			}
 		}, this);
 	},
@@ -101,9 +118,31 @@ BrowserUIShowHideObserver.prototype = {
 		delete this.owner;
 	},
 
+	dumpMutation : function BrowserUIShowHideObserver_dumpMutation(aMutation, aDescription)
+	{
+		if (!utils.isDebugging('browserUIShowHideObserver'))
+			return;
+
+		var target = aMutation.target;
+		var ownerInformation = this.box.localName + '#' + this.box.id + '.' + this.box.className;
+		var targetInformation = target.localName + '#' + target.id + '.' + target.className;
+		var attributeInformation = '';
+		if (aMutation.attributeName)
+			 attributeInformation = ' / ' +
+					aMutation.attributeName + ', ' +
+					aMutation.oldValue + ' => ' +
+					target.getAttribute(aMutation.attributeName);
+		dump(aDescription + ' ' +
+			ownerInformation + ' / ' +
+			targetInformation +
+			attributeInformation + '\n');
+	},
+
 	onAttributeModified : function BrowserUIShowHideObserver_onAttributeModified(aMutation, aObserver) 
 	{
-		if (this.handlingAttrChange)
+		var TST = this.owner.browser.treeStyleTab;
+		if (this.handlingAttrChange ||
+			TST.notifyingRenderedEvent)
 			return;
 
 		var target = aMutation.target;
@@ -111,7 +150,6 @@ BrowserUIShowHideObserver.prototype = {
 		if (target.__treestyletab_mutationObserver_lastState == state)
 			return;
 
-		var TST = this.owner.browser.treeStyleTab;
 		if (
 			// ignore modifications of each tab
 			TST.getTabFromChild(target) ||
@@ -124,34 +162,58 @@ BrowserUIShowHideObserver.prototype = {
 			)
 			return;
 
-		var toolbarVisible     = !TST.ownerToolbar.collapsed;
-		var tabbarVisible      = this.owner.browser.tabContainer.visible;
-		var placeHolderVisible = !TST.tabStripPlaceHolder.collapsed;
-		var tabbarVisibilityMismatching = (
-			toolbarVisible != placeHolderVisible ||
-			tabbarVisible  != placeHolderVisible
-		);
+		var tabbar = this.owner.browser.tabContainer;
+		var placeHolder = TST.tabStripPlaceHolder;
+
+		var tabbarVisibilityMismatching = false;
+		{
+			let toolbarVisible     = !TST.ownerToolbar.collapsed;
+			let tabbarVisible      = tabbar.visible;
+			let placeHolderVisible = !placeHolder.collapsed;
+			tabbarVisibilityMismatching = (
+				toolbarVisible != placeHolderVisible ||
+				tabbarVisible  != placeHolderVisible
+			);
+		}
+
+		var tabbarMatrixMismatching = false;
+		{
+			let tabbarBox         = tabbar.boxObject;
+			let tabbarMatrix      = JSON.stringify({
+				x: tabbarBox.screenX,
+				y: tabbarBox.screenY,
+				w: tabbarBox.width,
+				h: tabbarBox.height
+			});
+			let placeHolderBox    = placeHolder.boxObject;
+			let placeHolderMatrix = JSON.stringify({
+				x: placeHolderBox.screenX,
+				y: placeHolderBox.screenY,
+				w: placeHolderBox.width,
+				h: placeHolderBox.height
+			});
+			tabbarMatrixMismatching = tabbarMatrix != placeHolderMatrix;
+		}
 
 		if (
 			// I must ignore show/hide of elements managed by TST,
 			// to avoid infinity loop.
-			target.hasAttribute(TreeStyleTabConstants.kTAB_STRIP_ELEMENT) &&
+			TST.evaluateXPath(
+				'ancestor-or-self::xul:*[@' + TreeStyleTabConstants.kTAB_STRIP_ELEMENT + '="true"]',
+				target,
+				Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+			).singleNodeValue &&
 			// However, I have to synchronize visibility of the real
 			// tab bar and the placeholder's one. If they have
 			// different visibility, then the tab bar is shown or
 			// hidden by "auto hide tab bar" feature of someone
 			// (Pale Moon, Tab Mix Plus, etc.)
-			!tabbarVisibilityMismatching
+			!tabbarVisibilityMismatching &&
+			!tabbarMatrixMismatching
 			)
 			return;
 
-		if (DEBUG) {
-			dump('BrowserUIShowHideObserver_onAttributeModified ' +
-			     target.localName + '#' + target.id + '.' + target.className + ', ' +
-			     aMutation.attributeName + ', ' +
-			     aMutation.oldValue + ' => ' +
-			     target.getAttribute(aMutation.attributeName) + '\n');
-		}
+		this.dumpMutation(aMutation, 'BrowserUIShowHideObserver_onAttributeModified');
 
 		this.handlingAttrChange = true;
 
diff --git a/modules/constants.js b/modules/constants.js
index c1d4cbe..a3578ce 100644
--- a/modules/constants.js
+++ b/modules/constants.js
@@ -34,9 +34,9 @@
  *
  * ***** END LICENSE BLOCK ******/
  
-const EXPORTED_SYMBOLS = ['TreeStyleTabConstants']; 
+var EXPORTED_SYMBOLS = ['TreeStyleTabConstants']; 
 
-const TreeStyleTabConstants = Object.freeze({
+var TreeStyleTabConstants = Object.freeze({
 /* attributes */
 	kID                 : 'treestyletab-id',
 	kCHILDREN           : 'treestyletab-children',
@@ -82,7 +82,6 @@ const TreeStyleTabConstants = Object.freeze({
 	kFAVICONIZED        : 'treestyletab-faviconized',
 	kBG_NOTIFY_PHASE    : 'treestyletab-notifybgtab-phase',
 	kIGNORE_POPUP_STATE : 'treestyletab-ignore-state',
-	kDOM_FULLSCREEN_ACTIVATED : 'treestyletab-dom-fullscreen-activated',
 
 	kTAB_INVERTED          : 'treestyletab-tab-inverted',
 	kTAB_CONTENTS_INVERTED : 'treestyletab-tab-contents-inverted',
@@ -132,6 +131,7 @@ const TreeStyleTabConstants = Object.freeze({
 	kEVENT_TYPE_TABBAR_POSITION_CHANGED      : 'nsDOMTreeStyleTabTabbarPositionChanged',
 	kEVENT_TYPE_TABBAR_STATE_CHANGING        : 'nsDOMTreeStyleTabTabbarStateChanging',
 	kEVENT_TYPE_TABBAR_STATE_CHANGED         : 'nsDOMTreeStyleTabTabbarStateChanged',
+	kEVENT_TYPE_TABBAR_RENDERED              : 'nsDOMTreeStyleTabTabbarRendered',
 	kEVENT_TYPE_FOCUS_NEXT_TAB               : 'nsDOMTreeStyleTabFocusNextTab',
 	kEVENT_TYPE_ATTACHED                     : 'nsDOMTreeStyleTabAttached',
 	kEVENT_TYPE_DETACHED                     : 'nsDOMTreeStyleTabParted',
@@ -218,11 +218,12 @@ const TreeStyleTabConstants = Object.freeze({
 	RESTORE_STATE_STRUCTURE_RESTORED  : 2,
 
 
-//	CONTENT_SCRIPT          : 'chrome://treestyletab/content/content-utils.js',
+	CONTENT_SCRIPT          : 'chrome://treestyletab/content/content-utils.js',
 	CONTENT_SCRIPT_AUTOHIDE : 'chrome://treestyletab/content/content-utils-autohide.js',
 	MESSAGE_TYPE            : 'treestyletab',
 
 	COMMAND_SHUTDOWN                : 'shutdown',
+	COMMAND_REPORT_SELECTION_CHANGE : 'report-selection-change',
 	COMMAND_REPORT_MOUSEDOWN        : 'report-mousedown',
 	COMMAND_REPORT_MOUSEUP          : 'report-mouseup',
 	COMMAND_REPORT_MOUSEMOVE        : 'report-mousemove',
diff --git a/modules/contentBridge.js b/modules/contentBridge.js
index 8a90fd7..d7f34a4 100644
--- a/modules/contentBridge.js
+++ b/modules/contentBridge.js
@@ -33,9 +33,7 @@
  *
  * ***** END LICENSE BLOCK ******/
  
-const EXPORTED_SYMBOLS = ['ContentBridge']; 
-
-const DEBUG = false;
+var EXPORTED_SYMBOLS = ['ContentBridge']; 
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
@@ -46,12 +44,15 @@ Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
 Cu.import('resource://treestyletab-modules/constants.js');
 Cu.import('resource://gre/modules/Promise.jsm');
 
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+
 function ContentBridge(aTab, aTabBrowser) 
 {
 	this.init(aTab, aTabBrowser);
 }
 
 ContentBridge.install = function CB_installScript(aWindow) {
+	aWindow.messageManager.loadFrameScript(TreeStyleTabConstants.CONTENT_SCRIPT, true);
 	aWindow.messageManager.loadFrameScript(TreeStyleTabConstants.CONTENT_SCRIPT_AUTOHIDE, true);
 };
 
@@ -59,6 +60,8 @@ ContentBridge.uninstall = function CB_installScript(aWindow) {
 	aWindow.messageManager.broadcastAsyncMessage(TreeStyleTabConstants.MESSAGE_TYPE, {
 		command : TreeStyleTabConstants.COMMAND_SHUTDOWN
 	});
+	aWindow.messageManager.removeDelayedFrameScript(TreeStyleTabConstants.CONTENT_SCRIPT);
+	aWindow.messageManager.removeDelayedFrameScript(TreeStyleTabConstants.CONTENT_SCRIPT_AUTOHIDE);
 };
  
 ContentBridge.prototype = inherit(TreeStyleTabConstants, { 
@@ -104,15 +107,21 @@ ContentBridge.prototype = inherit(TreeStyleTabConstants, {
 	},
 	handleMessage : function CB_handleMessage(aMessage)
 	{
-//		dump('*********************handleMessage*******************\n');
-//		dump('TARGET IS: '+aMessage.target.localName+'\n');
-//		dump(JSON.stringify(aMessage.json)+'\n');
+		if (utils.isDebugging('contentBridge')) {
+			dump('*********************handleMessage*******************\n');
+			dump('TARGET IS: '+aMessage.target.localName+'\n');
+			dump(JSON.stringify(aMessage.json)+'\n');
+		}
 
 		if (aMessage.target != this.mTab.linkedBrowser)
 		  return;
 
 		switch (aMessage.json.command)
 		{
+			case this.COMMAND_REPORT_SELECTION_CHANGE:
+				this.mTab.__treestyletab__lastContentSelectionText = aMessage.json.text;
+				return;
+
 			case this.COMMAND_REPORT_MOUSEDOWN:
 				{
 					let fakeEvent = this.fixupEventCoordinates(aMessage.json.event);
diff --git a/modules/fullTooltip.js b/modules/fullTooltip.js
index 7962f2f..9457d87 100644
--- a/modules/fullTooltip.js
+++ b/modules/fullTooltip.js
@@ -34,7 +34,7 @@
  *
  * ***** END LICENSE BLOCK ******/
 
-const EXPORTED_SYMBOLS = ['FullTooltipManager'];
+var EXPORTED_SYMBOLS = ['FullTooltipManager'];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
diff --git a/modules/fullscreenObserver.js b/modules/fullscreenObserver.js
index 368eb87..6dcd7de 100644
--- a/modules/fullscreenObserver.js
+++ b/modules/fullscreenObserver.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2013
+ * Portions created by the Initial Developer are Copyright (C) 2013-2015
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -33,7 +33,9 @@
  *
  * ***** END LICENSE BLOCK ******/
 
-const EXPORTED_SYMBOLS = ['FullscreenObserver']; 
+var EXPORTED_SYMBOLS = ['FullscreenObserver']; 
+
+Components.utils.import('resource://treestyletab-modules/constants.js');
 
 Components.utils.import('resource://treestyletab-modules/utils.js');
 
@@ -57,10 +59,11 @@ FullscreenObserver.prototype = {
 		}).bind(this));
 		this.observer.observe(this.window.document.documentElement, {
 			attributes      : true,
+			attributeOldValue: true,
 			attributeFilter : ['sizemode']
 		});
 
-		this.onSizeModeChange();
+		this.window.setTimeout(this.onSizeModeChange.bind(this), 0);
 	},
 
 	destroy : function FullscreenObserver_destroy()
@@ -74,6 +77,12 @@ FullscreenObserver.prototype = {
 
 	onMutation : function FullscreenObserver_onMutation(aMutations, aObserver) 
 	{
+		var anyChanged = aMutations.some(function(aMutation) {
+			var newValue = aMutation.target.getAttribute(aMutation.attributeName);
+			return aMutation.oldValue !== newValue;
+		}, this);
+		if (!anyChanged)
+			return;
 		this.window.setTimeout((function() {
 			this.onSizeModeChange();
 		}).bind(this), 10);
@@ -81,6 +90,12 @@ FullscreenObserver.prototype = {
 
 	onSizeModeChange : function FullscreenObserver_onSizeModeChange()
 	{
+		this.updateToolboxPosition();
+		if (!this.window.gBrowser.treeStyleTab.notifyingRenderedEvent)
+			this.window.gBrowser.treeStyleTab.updateFloatingTabbar(TreeStyleTabConstants.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
+	},
+	updateToolboxPosition : function FullscreenObserver_onSizeModeChange()
+	{
 		var w = this.window;
 		var d = w.document;
 		if (d.documentElement.getAttribute('sizemode') != 'fullscreen')
diff --git a/modules/groupTab.js b/modules/groupTab.js
index c53725e..080f1b4 100644
--- a/modules/groupTab.js
+++ b/modules/groupTab.js
@@ -34,7 +34,7 @@
  *
  * ***** END LICENSE BLOCK ******/
 
-const EXPORTED_SYMBOLS = ['GroupTab']; 
+var EXPORTED_SYMBOLS = ['GroupTab']; 
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
diff --git a/modules/lib/inherit.jsm b/modules/lib/inherit.jsm
index 72ce625..cb7730e 100644
--- a/modules/lib/inherit.jsm
+++ b/modules/lib/inherit.jsm
@@ -10,7 +10,7 @@
  * @url http://github.com/piroor/fxaddonlib-inherit
  */
 
-const EXPORTED_SYMBOLS = ['inherit'];
+var EXPORTED_SYMBOLS = ['inherit'];
 
 function toPropertyDescriptors(aProperties) {
 	var descriptors = {};
diff --git a/modules/pseudoTreeBuilder.js b/modules/pseudoTreeBuilder.js
index de5ecf9..5907d54 100644
--- a/modules/pseudoTreeBuilder.js
+++ b/modules/pseudoTreeBuilder.js
@@ -34,7 +34,7 @@
  *
  * ***** END LICENSE BLOCK ******/
 
-const EXPORTED_SYMBOLS = ['PseudoTreeBuilder'];
+var EXPORTED_SYMBOLS = ['PseudoTreeBuilder'];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
diff --git a/modules/tabAttributesObserver.js b/modules/tabAttributesObserver.js
index 7f81598..8a62231 100644
--- a/modules/tabAttributesObserver.js
+++ b/modules/tabAttributesObserver.js
@@ -33,7 +33,7 @@
  *
  * ***** END LICENSE BLOCK ******/
 
-const EXPORTED_SYMBOLS = ['TabAttributesObserver']; 
+var EXPORTED_SYMBOLS = ['TabAttributesObserver']; 
 
 Components.utils.import('resource://treestyletab-modules/constants.js');
 
diff --git a/modules/tabbarDNDObserver.js b/modules/tabbarDNDObserver.js
index dfd2598..e45033e 100644
--- a/modules/tabbarDNDObserver.js
+++ b/modules/tabbarDNDObserver.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2014
+ * Portions created by the Initial Developer are Copyright (C) 2010-2015
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -35,9 +35,7 @@
  *
  * ***** END LICENSE BLOCK ******/
  
-const EXPORTED_SYMBOLS = ['TabbarDNDObserver']; 
-
-const DEBUG = false;
+var EXPORTED_SYMBOLS = ['TabbarDNDObserver']; 
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
@@ -45,6 +43,7 @@ const Cu = Components.utils;
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Services.jsm');
+Cu.import('resource://treestyletab-modules/ReferenceCounter.js');
 
 XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
 
@@ -188,7 +187,8 @@ try{
 		return info.canDrop;
 }
 catch(e) {
-		dump('TabbarDND::canDrop\n'+e+'\n');
+		if (utils.isDebugging('tabbarDNDObserver'))
+			dump('TabbarDND::canDrop\n'+e+'\n');
 		return false;
 }
 	},
@@ -262,7 +262,8 @@ catch(e) {
 	
 	getDropActionInternal : function TabbarDND_getDropActionInternal(aEvent, aSourceTab) 
 	{
-		if (DEBUG) dump('getDropActionInternal: start\n');
+		if (utils.isDebugging('tabbarDNDObserver'))
+			dump('getDropActionInternal: start\n');
 		var sv = this.treeStyleTab;
 		var b  = this.browser;
 		var d  = this.document;
@@ -303,18 +304,21 @@ catch(e) {
 		var isNewTabAction = !aSourceTab || aSourceTab.ownerDocument != d;
 
 		if (!tab || tab.localName != 'tab') {
-			if (DEBUG) dump('  not on a tab\n');
+			if (utils.isDebugging('tabbarDNDObserver'))
+				dump('  not on a tab\n');
 			let action = isTabMoveFromOtherWindow ? sv.kACTION_STAY : (sv.kACTION_MOVE | sv.kACTION_PART) ;
 			if (isNewTabAction) action |= sv.kACTION_NEWTAB;
 			if (aEvent[sv.screenPositionProp] < sv.getTabActualScreenPosition(firstTab)) {
-				if (DEBUG) dump('  above the first tab\n');
+				if (utils.isDebugging('tabbarDNDObserver'))
+					dump('  above the first tab\n');
 				info.target   = info.parent = info.insertBefore = firstTab;
 				info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ;
 				info.action   = action;
 				return info;
 			}
 			else if (aEvent[sv.screenPositionProp] > sv.getTabActualScreenPosition(tabs[lastTabIndex]) + tabs[lastTabIndex].boxObject[sv.sizeProp]) {
-				if (DEBUG) dump('  below the last tab\n');
+				if (utils.isDebugging('tabbarDNDObserver'))
+					dump('  below the last tab\n');
 				info.target   = info.parent = tabs[lastTabIndex];
 				info.position = isInverted ? sv.kDROP_BEFORE : sv.kDROP_AFTER ;
 				info.action   = action;
@@ -324,25 +328,30 @@ catch(e) {
 				let index = b.getNewIndex ?
 								b.getNewIndex(aEvent) :
 								b.tabContainer._getDropIndex(aEvent) ;
-				if (DEBUG) dump('  on the tab '+index+'\n');
+				if (utils.isDebugging('tabbarDNDObserver'))
+					dump('  on the tab '+index+'\n');
 				index = Math.min(index, lastTabIndex);
 				info.target = tab = tabs[index];
 				if (index == tabs[lastTabIndex]._tPos) {
 					if (index > 0)
 						info.target = tab = tabs[index - 1];
 					info.position = sv.kDROP_AFTER;
-					if (DEBUG) dump('  => after the last tab\n');
+					if (utils.isDebugging('tabbarDNDObserver'))
+						dump('  => after the last tab\n');
 				} else if (index == firstTab._tPos) {
 					if (index < lastTabIndex - 1)
 						info.target = tab = tabs[index + 1];
 					info.position = sv.kDROP_BEFORE;
-					if (DEBUG) dump('  => before the first tab\n');
+					if (utils.isDebugging('tabbarDNDObserver'))
+						dump('  => before the first tab\n');
 				}
-				if (DEBUG) dump('  info.target = ' + info.target._tPos + '\n');
+				if (utils.isDebugging('tabbarDNDObserver'))
+					dump('  info.target = ' + info.target._tPos + '\n');
 			}
 		}
 		else {
-			if (DEBUG) dump('  on the tab '+tab._tPos+'\n');
+			if (utils.isDebugging('tabbarDNDObserver'))
+				dump('  on the tab '+tab._tPos+'\n');
 			sv.ensureTabInitialized(tab);
 			info.target = tab;
 		}
@@ -378,18 +387,21 @@ catch(e) {
 		switch (info.position)
 		{
 			case sv.kDROP_ON:
-				if (DEBUG) dump('  position = on the tab\n');
+				if (utils.isDebugging('tabbarDNDObserver'))
+					dump('  position = on the tab\n');
 				var visible = sv.getNextVisibleTab(tab);
 				info.action       = sv.kACTION_STAY | sv.kACTION_ATTACH;
 				info.parent       = tab;
 				info.insertBefore = utils.getTreePref('insertNewChildAt') == sv.kINSERT_FISRT ?
 						(sv.getFirstChildTab(tab) || visible) :
 						(sv.getNextSiblingTab(tab) || sv.getNextTab(sv.getLastDescendantTab(tab) || tab));
-				if (DEBUG && info.insertBefore) dump('  insertBefore = '+info.insertBefore._tPos+'\n');
+				if (utils.isDebugging('tabbarDNDObserver') && info.insertBefore)
+					dump('  insertBefore = '+info.insertBefore._tPos+'\n');
 				break;
 
 			case sv.kDROP_BEFORE:
-				if (DEBUG) dump('  position = before the tab\n');
+				if (utils.isDebugging('tabbarDNDObserver'))
+					dump('  position = before the tab\n');
 /*
 	     <= detach from parent, and move
 	[TARGET  ]
@@ -425,11 +437,13 @@ catch(e) {
 					info.action       = sv.kACTION_MOVE | (info.parent ? sv.kACTION_ATTACH : sv.kACTION_PART );
 					info.insertBefore = tab;
 				}
-				if (DEBUG && info.insertBefore) dump('  insertBefore = '+info.insertBefore._tPos+'\n');
+				if (utils.isDebugging('tabbarDNDObserver') && info.insertBefore)
+					dump('  insertBefore = '+info.insertBefore._tPos+'\n');
 				break;
 
 			case sv.kDROP_AFTER:
-				if (DEBUG) dump('  position = after the tab\n');
+				if (utils.isDebugging('tabbarDNDObserver'))
+					dump('  position = after the tab\n');
 /*
 	[TARGET  ]
 	     <= if the target has a parent, attach to it and and move
@@ -473,7 +487,8 @@ catch(e) {
 						}
 					}
 				}
-				if (DEBUG && info.insertBefore) dump('  insertBefore = '+info.insertBefore._tPos+'\n');
+				if (utils.isDebugging('tabbarDNDObserver') && info.insertBefore)
+					dump('  insertBefore = '+info.insertBefore._tPos+'\n');
 				break;
 		}
 
@@ -484,14 +499,16 @@ catch(e) {
   
 	performDrop : function TabbarDND_performDrop(aInfo, aDraggedTab) 
 	{
-		if (DEBUG) dump('performDrop: start\n');
+		if (utils.isDebugging('tabbarDNDObserver'))
+			dump('performDrop: start\n');
 		var sv = this.treeStyleTab;
 		var b  = this.browser;
 		var w  = this.window;
 
 		var tabsInfo = this.getDraggedTabsInfoFromOneTab(aDraggedTab, aInfo);
 		if (!tabsInfo.draggedTab) {
-			if (DEBUG) dump(' => no dragged tab\n');
+			if (utils.isDebugging('tabbarDNDObserver'))
+				dump(' => no dragged tab\n');
 			return false;
 		}
 
@@ -548,7 +565,8 @@ catch(e) {
 				sourceBrowser == targetBrowser &&
 				sourceService.getNextVisibleTab(draggedTabs[draggedTabs.length-1]) == aInfo.insertBefore
 				) {
-				if (DEBUG) dump(' => no change\n');
+				if (utils.isDebugging('tabbarDNDObserver'))
+					dump(' => no change\n');
 				// then, do nothing
 				return true;
 			}
@@ -951,7 +969,13 @@ try{
 		var info = this.getDropAction(aEvent, session);
 
 		var observer = b;
-		if (b.tabContainer && b.tabContainer._setEffectAllowedForDataTransfer)
+		if (
+			b.tabContainer &&
+			(
+				b.tabContainer._getDropEffectForTabDrag || // Firefox 44 and later
+				b.tabContainer._setEffectAllowedForDataTransfer // Firefox 43 and older
+			)
+			)
 			observer = b.tabContainer;
 
 		// auto-switch for staying on tabs
@@ -963,7 +987,9 @@ try{
 			) {
 			let time = observer.mDragTime || observer._dragTime || 0;
 			let delay = observer.mDragOverDelay || observer._dragOverDelay || 0;
-			let effects = observer._setEffectAllowedForDataTransfer(aEvent);
+			let effects = '_setEffectAllowedForDataTransfer' in observer ?
+							observer._setEffectAllowedForDataTransfer(aEvent) :
+							observer._getDropEffectForTabDrag(aEvent) ;
 			if (effects == 'link') {
 				let now = Date.now();
 				if (!time) {
@@ -978,14 +1004,20 @@ try{
 			}
 		}
 
+		{
+			let effects = '_setEffectAllowedForDataTransfer' in observer ?
+							observer._setEffectAllowedForDataTransfer(aEvent) :
+							observer._getDropEffectForTabDrag(aEvent) ;
+
 		if (
 			!info.canDrop ||
-			observer._setEffectAllowedForDataTransfer(aEvent) == 'none'
+			effects == 'none'
 			) {
 			aEvent.dataTransfer.effectAllowed = "none";
 			this.clearDropPosition();
 			return true;
 		}
+		}
 
 		let indicatorTab = info.target;
 		if (sv.isCollapsed(info.target)) {
@@ -1021,7 +1053,8 @@ try{
 		return (info.position == sv.kDROP_ON || sv.position != 'top')
 }
 catch(e) {
-	dump('TabbarDND::onDragOver\n'+e+'\n');
+		if (utils.isDebugging('tabbarDNDObserver'))
+			dump('TabbarDND::onDragOver\n'+e+'\n');
 }
 	},
   
@@ -1066,7 +1099,15 @@ catch(e) {
 			tabbar._tabDropIndicator.collapsed = true;
 
 		var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
-		if (dt.dropEffect != 'link' && !draggedTab) {
+
+		if (utils.isDebugging('tabbarDNDObserver'))
+			dump('TabbarDND::onDrop\n' +
+				'  dt.dropEffect: ' + dt.dropEffect + '\n' +
+				'  draggedTab:    ' + draggedTab + '\n');
+
+		if (dt.dropEffect != 'link' &&
+			dt.dropEffect != 'move' &&
+			!draggedTab) {
 			aEvent.stopPropagation();
 			return;
 		}
@@ -1132,6 +1173,9 @@ catch(e) {
 				if (aURI.indexOf(this.BOOKMARK_FOLDER) == 0) {
 					let newTabs = sv.getNewTabsWithOperation(function() {
 									var data = aURI.replace(self.BOOKMARK_FOLDER, '');
+									if (utils.isDebugging('tabbarDNDObserver'))
+										dump('TabbarDND::handleLinksOrBookmarks\n' +
+											'  bookmark folder data: ' + data + '\n');
 									data = JSON.parse(data);
 									w.PlacesUIUtils._openTabset(data.children, { type : 'drop' }, w, data.title);
 								}, b);
@@ -1143,8 +1187,12 @@ catch(e) {
 					this.performDrop(aDropActionInfo, newTabs[0]);
 				}
 				else {
-					aURI = utils.getShortcutOrURI(w, aURI);
-					this.performDrop(aDropActionInfo, b.loadOneTab(aURI, { inBackground: bgLoad }));
+					// TODO: The callback (for Firefox 38 and older) should be
+					// migrated to a Promise (Firefox 39 and later).
+					w.getShortcutOrURIAndPostData(aURI, (function(aData) {
+						var uri = aData.url;
+						this.performDrop(aDropActionInfo, b.loadOneTab(uri, { inBackground: bgLoad }));
+					}).bind(this));
 				}
 			}, this);
 		}
@@ -1158,8 +1206,10 @@ catch(e) {
 				aDropActionInfo.position == sv.kDROP_ON)
 				loadDroppedLinkToNewChildTab = sv.dropLinksOnTabBehavior() == sv.kDROPLINK_NEWTAB;
 
-			try {
-				let uri = utils.getShortcutOrURI(w, uris[0]);
+			// TODO: The callback (for Firefox 38 and older) should be
+			// migrated to a Promise (Firefox 39 and later).
+			w.getShortcutOrURIAndPostData(uris[0], (function(aData) {
+				var uri = aData.url;
 				if (loadDroppedLinkToNewChildTab || locked) {
 					this.performDrop(aDropActionInfo, b.loadOneTab(uri, { inBackground: bgLoad }));
 				}
@@ -1168,9 +1218,7 @@ catch(e) {
 					if (!bgLoad)
 						b.selectedTab = tab;
 				}
-			}
-			catch(e) {
-			}
+			}).bind(this));
 		}
 	},
 	securityCheck : function TabbarDND_securityCheck(aURI, aEvent)
@@ -1248,8 +1296,12 @@ catch(e) {
 				{
 					let item = JSON.parse(aData);
 					if (item.type == 'text/x-moz-place-container') {
-						// When a blank folder is dropped, just open a dummy tab with the folder name.
 						let children = item.children;
+						if (!children) {
+							children = item.children = this.retrieveBookmarksInFolder(item.id);
+							aData = JSON.stringify(item);
+						}
+						// When a blank folder is dropped, just open a dummy tab with the folder name.
 						if (children && children.length == 0) {
 							let uri = this.treeStyleTab.getGroupTabURI({ title: item.title });
 							return [uri];
@@ -1284,6 +1336,20 @@ catch(e) {
 		}
 		return [];
 	},
+	retrieveBookmarksInFolder : function TabbarDND_retrieveBookmarksInFolder(aId)
+	{
+		var PlacesUtils = this.window.PlacesUtils;
+		var folder = PlacesUtils.getFolderContents(aId, false, true).root;
+		var children = [];
+		for (let i = 0; i < folder.childCount; i++) {
+			let child = folder.getChild(i);
+			if (PlacesUtils.nodeIsURI(child)) {
+				let item = PlacesUtils.wrapNode(child, 'text/x-moz-place');
+				children.push(JSON.parse(item));
+			}
+		}
+		return children;
+	},
     
 	init : function TabbarDND_init(aTabBrowser) 
 	{
@@ -1302,11 +1368,17 @@ catch(e) {
 	{
 		var target = this.treeStyleTab.ownerToolbar || this.treeStyleTab.tabStrip;
 		target.addEventListener('dragstart', this, true);
+		ReferenceCounter.add('target,dragstart,TabbarDND,true');
 		target.addEventListener('dragover',  this, true);
+		ReferenceCounter.add('target,dragover,TabbarDND,true');
 		target.addEventListener('dragenter', this, false);
+		ReferenceCounter.add('target,dragenter,TabbarDND,false');
 		target.addEventListener('dragleave', this, false);
+		ReferenceCounter.add('target,dragleave,TabbarDND,false');
 		target.addEventListener('dragend',   this, true);
+		ReferenceCounter.add('target,dragend,TabbarDND,true');
 		target.addEventListener('drop',      this, true);
+		ReferenceCounter.add('target,drop,TabbarDND,true');
 	},
   
 	destroy : function TabbarDND_destroy() 
@@ -1323,11 +1395,17 @@ catch(e) {
 	{
 		var target = this.treeStyleTab.ownerToolbar || this.treeStyleTab.tabStrip;
 		target.removeEventListener('dragstart', this, true);
+		ReferenceCounter.remove('target,dragstart,TabbarDND,true');
 		target.removeEventListener('dragover',  this, true);
+		ReferenceCounter.remove('target,dragover,TabbarDND,true');
 		target.removeEventListener('dragenter', this, false);
+		ReferenceCounter.remove('target,dragenter,TabbarDND,false');
 		target.removeEventListener('dragleave', this, false);
+		ReferenceCounter.remove('target,dragleave,TabbarDND,false');
 		target.removeEventListener('dragend',   this, true);
+		ReferenceCounter.remove('target,dragend,TabbarDND,true');
 		target.removeEventListener('drop',      this, true);
+		ReferenceCounter.remove('target,drop,TabbarDND,true');
 	}
   
 }; 
diff --git a/modules/tabpanelDNDObserver.js b/modules/tabpanelDNDObserver.js
index 69689c5..d2eee66 100644
--- a/modules/tabpanelDNDObserver.js
+++ b/modules/tabpanelDNDObserver.js
@@ -34,12 +34,13 @@
  *
  * ***** END LICENSE BLOCK ******/
  
-const EXPORTED_SYMBOLS = ['TabpanelDNDObserver'];
+var EXPORTED_SYMBOLS = ['TabpanelDNDObserver'];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js');
 
 XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
 
@@ -145,16 +146,22 @@ TabpanelDNDObserver.prototype = {
 
 		var b = this.treeStyleTab.mTabBrowser;
 		b.mPanelContainer.addEventListener('dragover',  this, true);
+		ReferenceCounter.add('b.mPanelContainer,dragover,this,true');
 		b.mPanelContainer.addEventListener('dragleave', this, true);
+		ReferenceCounter.add('b.mPanelContainer,dragleave,this,true');
 		b.mPanelContainer.addEventListener('drop',      this, true);
+		ReferenceCounter.add('b.mPanelContainer,drop,this,true');
 	},
  
 	destroy : function TabpanelDND_destroy() 
 	{
 		var b = this.treeStyleTab.mTabBrowser;
 		b.mPanelContainer.removeEventListener('dragover',  this, true);
+		ReferenceCounter.remove('b.mPanelContainer,dragover,this,true');
 		b.mPanelContainer.removeEventListener('dragleave', this, true);
+		ReferenceCounter.remove('b.mPanelContainer,dragleave,this,true');
 		b.mPanelContainer.removeEventListener('drop',      this, true);
+		ReferenceCounter.remove('b.mPanelContainer,drop,this,true');
 
 		delete this.treeStyleTab;
 		delete this.browser;
diff --git a/modules/themeManager.js b/modules/themeManager.js
index 1cc1105..26126a6 100644
--- a/modules/themeManager.js
+++ b/modules/themeManager.js
@@ -34,7 +34,7 @@
  *
  * ***** END LICENSE BLOCK ******/
  
-const EXPORTED_SYMBOLS = ['TreeStyleTabThemeManager']; 
+var EXPORTED_SYMBOLS = ['TreeStyleTabThemeManager']; 
 
 const BASE = 'chrome://treestyletab/skin/';
 
diff --git a/modules/utils.js b/modules/utils.js
index a3a2f7b..240602f 100644
--- a/modules/utils.js
+++ b/modules/utils.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2014
+ * Portions created by the Initial Developer are Copyright (C) 2010-2015
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -36,7 +36,7 @@
 
 "use strict";
 
-let EXPORTED_SYMBOLS = ['TreeStyleTabUtils'];
+var EXPORTED_SYMBOLS = ['TreeStyleTabUtils'];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
@@ -61,14 +61,16 @@ XPCOMUtils.defineLazyGetter(this, 'stringBundle', function() {
 
 XPCOMUtils.defineLazyModuleGetter(this, 'Task',
 	'resource://gre/modules/Task.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Promise',
+	'resource://gre/modules/Promise.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'TreeStyleTabConstants',
   'resource://treestyletab-modules/constants.js', 'TreeStyleTabConstants');
 
 const TST_PREF_PREFIX = 'extensions.treestyletab.';
-const TST_PREF_VERSION = 10;
+const TST_PREF_VERSION = 11;
 
 
-let TreeStyleTabUtils = {
+var TreeStyleTabUtils = {
 
 	get prefs () {
 		return prefs;
@@ -213,6 +215,12 @@ let TreeStyleTabUtils = {
 						this.setTreePref('openGroupBookmark.behavior', behavior);
 					}
 				}
+			case 10:
+				{
+					let physical = this.getTreePref('maxTreeLevel.phisical');
+					this.setTreePref('maxTreeLevel.physical', physical);
+					this.clearTreePref('maxTreeLevel.phisical');
+				}
 			default:
 				for (let i = 0, maxi = orientalPrefs.length; i < maxi; i++)
 				{
@@ -229,6 +237,11 @@ let TreeStyleTabUtils = {
 		}
 		this.setTreePref('prefsVersion', TST_PREF_VERSION);
 	},
+ 
+	isDebugging : function utils_isDebugging(aModule)
+	{
+		return this.getTreePref('debug.' + aModule) || this.getTreePref('debug.all');
+	},
 
 /* string bundle */
 	get treeBundle () {
@@ -253,32 +266,16 @@ let TreeStyleTabUtils = {
 	isTabNotRestoredYet : function utils_isTabNotRestoredYet(aTab)
 	{
 		var browser = aTab.linkedBrowser;
-		// Firefox 25 and later. See: https://bugzilla.mozilla.org/show_bug.cgi?id=867142
-		if (this.TabRestoreStates &&
-			this.TabRestoreStates.has(browser))
-			return (
-				this.TabRestoreStates.isNeedsRestore(browser) ||
-				this.TabRestoreStates.isRestoring(browser)
-			);
-
 		return !!browser.__SS_restoreState;
 	},
 	isTabNeedToBeRestored : function utils_isTabNeedToBeRestored(aTab)
 	{
 		var browser = aTab.linkedBrowser;
-		// Firefox 25 and later. See: https://bugzilla.mozilla.org/show_bug.cgi?id=867142
-		if (this.TabRestoreStates &&
-			this.TabRestoreStates.has(browser))
-			return this.TabRestoreStates.isNeedsRestore(browser);
-
 		return browser.__SS_restoreState == 1;
 	},
 	get SessionStoreInternal() {
 		return this.SessionStoreNS.SessionStoreInternal;
 	},
-	get TabRestoreStates() {
-		return this.SessionStoreNS.TabRestoreStates;
-	},
 	get SessionStoreNS() {
 		if (!this._SessionStoreNS) {
 			try {
@@ -292,24 +289,6 @@ let TreeStyleTabUtils = {
 		return this._SessionStoreNS;
 	},
 
-	getShortcutOrURI : function utils_getShortcutOrURI(aBrowserWindow, aURI)
-	{
-		var done = false;
-		aBrowserWindow.getShortcutOrURIAndPostData(aURI, function(aData) {
-			aURI = aData.url;
-			done = true;
-		});
-
-		// this should be rewritten in asynchronous style...
-		var thread = Cc['@mozilla.org/thread-manager;1'].getService().mainThread;
-		while (!done)
-		{
-			thread.processNextEvent(true);
-		}
-
-		return aURI;
-	},
-
 
 	doPatching : function utils_assertFunctionExists(aFunction, aName, aPatchingTask, aMatcher)
 	{
@@ -375,3 +354,18 @@ let TreeStyleTabUtils = {
 };
 
 prefs.addPrefListener(TreeStyleTabUtils);
+
+{
+	// Never save TST specific attributes! (because it causes many problems)
+	let { TabAttributesInternal } = Cu.import('resource:///modules/sessionstore/TabAttributes.jsm', {});
+	if (TabAttributesInternal && TabAttributesInternal._skipAttrs) {
+		Object.keys(TreeStyleTabConstants).forEach(function(aKey) {
+			if (!/^k[A-Z_]+$/.test(aKey))
+				return;
+			var name = TreeStyleTabConstants[aKey];
+			if (!/^treestyletab-/.test(String(name)))
+				return;
+			TabAttributesInternal._skipAttrs.add(name);
+		});
+	}
+}
diff --git a/modules/window.js b/modules/window.js
index 424f346..866a890 100644
--- a/modules/window.js
+++ b/modules/window.js
@@ -34,7 +34,7 @@
  *
  * ***** END LICENSE BLOCK ******/
  
-const EXPORTED_SYMBOLS = ['TreeStyleTabWindow']; 
+var EXPORTED_SYMBOLS = ['TreeStyleTabWindow']; 
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
@@ -43,6 +43,7 @@ const Cu = Components.utils;
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Timer.jsm');
 Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
+Cu.import('resource://treestyletab-modules/ReferenceCounter.js');
 
 XPCOMUtils.defineLazyGetter(this, 'window', function() {
 	Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
@@ -80,7 +81,9 @@ function TreeStyleTabWindow(aWindow)
 	this.restoringCount = 0;
 
 	aWindow.addEventListener('DOMContentLoaded', this, true);
+	ReferenceCounter.add('w,DOMContentLoaded,TSTWindow,true');
 	aWindow.addEventListener('load', this, false);
+	ReferenceCounter.add('w,load,TSTWindow,false');
 	aWindow.TreeStyleTabService = this;
 
 	XPCOMUtils.defineLazyModuleGetter(aWindow, 'TreeStyleTabBrowser', 'resource://treestyletab-modules/browser.js');
@@ -188,6 +191,11 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 		return this.document.getElementById('browser-bottombox');
 	},
  
+	get socialBox() 
+	{
+		return this.document.getElementById('social-sidebar-box');
+	},
+ 
 	get isPopupWindow() 
 	{
 		return (
@@ -280,7 +288,20 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 			return false;
 		}
 
-		var selection = this.window.getBrowserSelection();
+		var selection = '';
+		var contextMenuContentData = this.window.gContextMenuContentData;
+		if (contextMenuContentData && contextMenuContentData.selectionInfo) {
+			selection = contextMenuContentData.selectionInfo.text;
+		}
+		else {
+			let tab = this.window.gBrowser.selectedTab;
+			selection = tab.__treestyletab__lastContentSelectionText || '';
+			// for old Firefox without selectionchange event
+			if (selection === '' &&
+				typeof this.window.getBrowserSelection === 'function' &&
+				tab.linkedBrowser.getAttribute('remote') !== 'true')
+				selection = this.window.getBrowserSelection();
+		}
 		return selection.trim() == aTerm;
 	},
 	kSEARCH_RESULT_DO_NOT_ATTACH      : 0,
@@ -298,7 +319,7 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
  
 	get autoHideWindow() 
 	{
-		if (!this._autoHideWindow) {
+		if (!('_autoHideWindow' in this)) {
 			this._autoHideWindow = new AutoHideWindow(this.window);
 		}
 		return this._autoHideWindow;
@@ -306,7 +327,7 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
  
 	get themeManager() 
 	{
-		if (!this._themeManager) {
+		if (!('_themeManager' in this)) {
 			this._themeManager = new TreeStyleTabThemeManager(this.window);
 		}
 		return this._themeManager;
@@ -359,10 +380,12 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 
 		var w = this.window;
 		w.removeEventListener('DOMContentLoaded', this, true);
+		ReferenceCounter.remove('w,DOMContentLoaded,TSTWindow,true');
 		if (w.location.href.indexOf('chrome://browser/content/browser.xul') != 0)
 			return;
 
 		w.addEventListener('SSTabRestoring', this, true);
+		ReferenceCounter.add('w,SSTabRestoring,TSTWindow,true');
 
 		w.TreeStyleTabWindowHelper.preInit();
 
@@ -375,8 +398,10 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 	{
 		var w = this.window;
 		w.removeEventListener('load', this, false);
+		ReferenceCounter.remove('w,load,TSTWindow,false');
 
 		w.addEventListener('unload', this, false);
+		ReferenceCounter.add('w,unload,TSTWindow,false');
 
 		if (
 			w.location.href.indexOf('chrome://browser/content/browser.xul') != 0 ||
@@ -391,28 +416,43 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 			this.preInit();
 		}
 		w.removeEventListener('SSTabRestoring', this, true);
+		ReferenceCounter.remove('w,SSTabRestoring,TSTWindow,true');
 
 		var d = this.document;
 		d.addEventListener('popupshowing', this, false);
+		ReferenceCounter.add('d,popupshowing,TSTWindow,false');
 		d.addEventListener('popuphiding', this, true);
+		ReferenceCounter.add('d,popuphiding,TSTWindow,true');
 		d.addEventListener(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, this, false);
+		ReferenceCounter.add('d,kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED,TSTWindow,false');
 		d.addEventListener(this.kEVENT_TYPE_TABBAR_POSITION_CHANGED,     this, false);
+		ReferenceCounter.add('d,kEVENT_TYPE_TABBAR_POSITION_CHANGED,TSTWindow,false');
 		d.addEventListener(this.kEVENT_TYPE_TABBAR_STATE_CHANGED,        this, false);
+		ReferenceCounter.add('d,kEVENT_TYPE_TABBAR_STATE_CHANGED,TSTWindow,false');
 		d.addEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB,              this, false);
+		ReferenceCounter.add('d,kEVENT_TYPE_FOCUS_NEXT_TAB,TSTWindow,false');
 		w.addEventListener('beforecustomization', this, true);
+		ReferenceCounter.add('w,beforecustomization,TSTWindow,true');
 		w.addEventListener('aftercustomization', this, false);
+		ReferenceCounter.add('w,aftercustomization,TSTWindow,false');
 
 		w.messageManager.addMessageListener('SessionStore:restoreTabContentStarted', this);
 
 		this.fullscreenObserver = new FullscreenObserver(this.window);
 		this.initUIShowHideObserver();
+		if (!this.isMac)
+			this.initMenubarShowHideObserver();
 
 		var appcontent = d.getElementById('appcontent');
 		appcontent.addEventListener('SubBrowserAdded', this, false);
+		ReferenceCounter.add('appcontent,SubBrowserAdded,TSTWindow,false');
 		appcontent.addEventListener('SubBrowserRemoveRequest', this, false);
+		ReferenceCounter.add('appcontent,SubBrowserRemoveRequest,TSTWindow,false');
 
 		w.addEventListener('UIOperationHistoryUndo:TabbarOperations', this, false);
+		ReferenceCounter.add('w,UIOperationHistoryUndo:TabbarOperations,TSTWindow,false');
 		w.addEventListener('UIOperationHistoryRedo:TabbarOperations', this, false);
+		ReferenceCounter.add('w,UIOperationHistoryRedo:TabbarOperations,TSTWindow,false');
 
 		prefs.addPrefListener(this);
 
@@ -425,7 +465,7 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 		w.TreeStyleTabWindowHelper.onAfterBrowserInit();
 
 		this.processRestoredTabs();
-		this.updateTabsOnTop();
+		this.updateTabsInTitlebar();
 
 		this.autoHideWindow; // initialize
 
@@ -438,15 +478,6 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 	initUninstallationListener : function TSTWindow_initUninstallationListener() 
 	{
 		var restorePrefs = function() {
-				if (prefs.getPref('extensions.treestyletab.tabsOnTop.originalState')) {
-					prefs.clearPref('extensions.treestyletab.tabsOnTop.originalState');
-					try {
-						this.browser.treeStyleTab.position = 'top';
-					}
-					catch(e) {
-					}
-					this.window.TabsOnTop.enabled = true;
-				}
 			}.bind(this);
 		new UninstallationListener({
 			id : 'treestyletab at piro.sakura.ne.jp',
@@ -489,7 +520,10 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
  
 	initUIShowHideObserver : function TSTWindow_initUIShowHideObserver() 
 	{
-		this.rootElementObserver = new BrowserUIShowHideObserver(this, this.document.documentElement);
+		this.rootElementObserver = new BrowserUIShowHideObserver(this, this.document.documentElement, {
+			childList : false,
+			subtree   : false
+		});
 
 		var toolbox = this.browserToolbox;
 		if (toolbox)
@@ -502,6 +536,23 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 		var bottomBox = this.browserBottomBox;
 		if (bottomBox)
 			this.browserBottomBoxObserver = new BrowserUIShowHideObserver(this, bottomBox);
+
+		var socialBox = this.socialBox;
+		if (socialBox)
+			this.socialBoxObserver = new BrowserUIShowHideObserver(this, socialBox);
+	},
+ 
+	initMenubarShowHideObserver : function TSTWindow_initMenubarShowHideObserver() 
+	{
+		var w = this.window;
+		var MutationObserver = w.MutationObserver || w.MozMutationObserver;
+		this.menubarShowHideObserver = new MutationObserver((function(aMutations, aObserver) {
+			this.updateTabsInTitlebar();
+		}).bind(this));
+		this.menubarShowHideObserver.observe(w.document.getElementById('toolbar-menubar'), {
+			attributes      : true,
+			attributeFilter : ['autohide']
+		});
 	},
   
 	destroy : function TSTWindow_destroy() 
@@ -511,12 +562,15 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 			this.base.inWindowDestoructionProcess = true;
 			try {
 				w.removeEventListener('unload', this, false);
+				ReferenceCounter.remove('w,unload,TSTWindow,false');
+
+				w.TreeStyleTabWindowHelper.destroyToolbarItems();
 
 				this.autoHideWindow.destroy();
-				delete this._autoHideWindow;
+				this._autoHideWindow = undefined;
 
 				this.themeManager.destroy();
-				delete this._themeManager;
+				this._themeManager = undefined;
 
 				this.browser.treeStyleTab.saveCurrentState();
 				this.destroyTabBrowser(this.browser);
@@ -526,13 +580,21 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 
 				let d = this.document;
 				d.removeEventListener('popupshowing', this, false);
+				ReferenceCounter.remove('d,popupshowing,TSTWindow,false');
 				d.removeEventListener('popuphiding', this, true);
+				ReferenceCounter.remove('d,popuphiding,TSTWindow,true');
 				d.removeEventListener(this.kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED, this, false);
+				ReferenceCounter.remove('d,kEVENT_TYPE_TAB_COLLAPSED_STATE_CHANGED,TSTWindow,false');
 				d.removeEventListener(this.kEVENT_TYPE_TABBAR_POSITION_CHANGED,     this, false);
+				ReferenceCounter.remove('d,kEVENT_TYPE_TABBAR_POSITION_CHANGED,TSTWindow,false');
 				d.removeEventListener(this.kEVENT_TYPE_TABBAR_STATE_CHANGED,        this, false);
+				ReferenceCounter.remove('d,kEVENT_TYPE_TABBAR_STATE_CHANGED,TSTWindow,false');
 				d.removeEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB,              this, false);
+				ReferenceCounter.remove('d,kEVENT_TYPE_FOCUS_NEXT_TAB,TSTWindow,false');
 				w.removeEventListener('beforecustomization', this, true);
+				ReferenceCounter.remove('w,beforecustomization,TSTWindow,true');
 				w.removeEventListener('aftercustomization', this, false);
+				ReferenceCounter.remove('w,aftercustomization,TSTWindow,false');
 
 				w.messageManager.removeMessageListener('SessionStore:restoreTabContentStarted', this);
 
@@ -541,9 +603,10 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 				this.fullscreenObserver.destroy();
 				delete this.fullscreenObserver;
 
-				this.rootElementObserver.destroy();
-				delete this.rootElementObserver;
-
+				if (this.rootElementObserver) {
+					this.rootElementObserver.destroy();
+					delete this.rootElementObserver;
+				}
 				if (this.browserToolboxObserver) {
 					this.browserToolboxObserver.destroy();
 					delete this.browserToolboxObserver;
@@ -556,18 +619,32 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 					this.browserBottomBoxObserver.destroy();
 					delete this.browserBottomBoxObserver;
 				}
+				if (this.socialBoxObserver) {
+					this.socialBoxObserver.destroy();
+					delete this.socialBoxObserver;
+				}
+
+				if (this.menubarShowHideObserver) {
+					this.menubarShowHideObserver.disconnect();
+					delete this.menubarShowHideObserver;
+				}
 
 				for (let i = 0, maxi = this._tabFocusAllowance.length; i < maxi; i++)
 				{
 					w.removeEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, this._tabFocusAllowance[i], false);
+					ReferenceCounter.remove('w,kEVENT_TYPE_FOCUS_NEXT_TAB,_tabFocusAllowance['+i+'],false');
 				}
 
 				var appcontent = d.getElementById('appcontent');
 				appcontent.removeEventListener('SubBrowserAdded', this, false);
+				ReferenceCounter.remove('appcontent,SubBrowserAdded,TSTWindow,false');
 				appcontent.removeEventListener('SubBrowserRemoveRequest', this, false);
+				ReferenceCounter.remove('appcontent,SubBrowserRemoveRequest,TSTWindow,false');
 
 				w.removeEventListener('UIOperationHistoryUndo:TabbarOperations', this, false);
+				ReferenceCounter.remove('w,UIOperationHistoryUndo:TabbarOperations,TSTWindow,false');
 				w.removeEventListener('UIOperationHistoryRedo:TabbarOperations', this, false);
+				ReferenceCounter.remove('w,UIOperationHistoryRedo:TabbarOperations,TSTWindow,false');
 
 				prefs.removePrefListener(this);
 			}
@@ -624,7 +701,7 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 
 			case this.kEVENT_TYPE_TABBAR_POSITION_CHANGED:
 			case this.kEVENT_TYPE_TABBAR_STATE_CHANGED:
-				return this.updateTabsOnTop();
+				return this.updateTabsInTitlebar();
 
 			case this.kEVENT_TYPE_FOCUS_NEXT_TAB:
 				return this.onFocusNextTab(aEvent);
@@ -709,9 +786,13 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 		if (!this.keyEventListening) {
 			let w = this.window;
 			w.addEventListener('keydown',  this, true);
+			ReferenceCounter.add('w,keydown,TSTWindow,true');
 			w.addEventListener('keyup',    this, true);
+			ReferenceCounter.add('w,keyup,TSTWindow,true');
 			w.addEventListener('keypress', this, true);
+			ReferenceCounter.add('w,keypress,TSTWindow,true');
 			w.addEventListener('blur',     this, true);
+			ReferenceCounter.add('w,blur,TSTWindow,true');
 			this.keyEventListening = true;
 		}
 		this.keyEventListeningFlags |= aReason;
@@ -725,9 +806,13 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 		if (!this.keyEventListeningFlags && this.keyEventListening) {
 			let w = this.window;
 			w.removeEventListener('keydown',  this, true);
+			ReferenceCounter.remove('w,keydown,TSTWindow,true');
 			w.removeEventListener('keyup',    this, true);
+			ReferenceCounter.remove('w,keyup,TSTWindow,true');
 			w.removeEventListener('keypress', this, true);
+			ReferenceCounter.remove('w,keypress,TSTWindow,true');
 			w.removeEventListener('blur',     this, true);
+			ReferenceCounter.remove('w,blur,TSTWindow,true');
 			this.keyEventListening = false;
 		}
 	},
@@ -787,9 +872,9 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 
 		// this.accelKeyPressed = this.isAccelKeyPressed(aEvent);
 		this.accelKeyPressed = aEvent.ctrlKey || aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_CONTROL;
-		this.window.setTimeout(function(aSelf) {
-			aSelf.arrowKeyEventOnTab = null;
-		}, 10, this);
+		setTimeout((function() {
+			this.arrowKeyEventOnTab = null;
+		}).bind(this), 10);
 
 		var standBy = scrollDown = scrollUp = (!aEvent.altKey && this.accelKeyPressed);
 
@@ -921,6 +1006,7 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 			aEvent.currentTarget.setCapture(true);
 
 		aEvent.currentTarget.addEventListener('mousemove', this, false);
+		ReferenceCounter.add('currentTarget,mousemove,TSTWindow,false');
 
 		var b = this.getTabBrowserFromChild(aEvent.currentTarget);
 		var box = aEvent.currentTarget.id == 'treestyletab-tabbar-resizer-splitter' ?
@@ -944,6 +1030,7 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 			target.releaseCapture();
 
 		target.removeEventListener('mousemove', this, false);
+		ReferenceCounter.remove('currentTarget,mousemove,TSTWindow,false');
 
 		this.tabbarResizeStartWidth  = -1;
 		this.tabbarResizeStartHeight = -1;
@@ -1064,16 +1151,16 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 			)
 			return;
 
-		this.updateAeroPeekPreviewsTimer = w.setTimeout(function(aSelf) {
-			aSelf.updateAeroPeekPreviewsTimer = null;
+		this.updateAeroPeekPreviewsTimer = w.setTimeout((function() {
+			this.updateAeroPeekPreviewsTimer = null;
 			try {
-				aSelf.updateAeroPeekPreviewsInternal();
+				this.updateAeroPeekPreviewsInternal();
 			}
 			catch(e) {
 				dump(e+'\n');
-				aSelf.updateAeroPeekPreviews();
+				this.updateAeroPeekPreviews();
 			}
-		}, 250, this);
+		}).bind(this), 250);
 	},
 	updateAeroPeekPreviewsTimer : null,
 	updateAeroPeekPreviewsInternal : function TSTWindow_updateAeroPeekPreviewsInternal()
@@ -1102,54 +1189,42 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 		}, this);
 	},
  
-	updateTabsOnTop : function TSTWindow_updateTabsOnTop() 
+	updateTabsInTitlebar : function TSTWindow_updateTabsInTitlebar() 
 	{
 		if (
 			this.isPopupWindow ||
-			this.tabsOnTopChangingByUI ||
-			this.tabsOnTopChangingByTST
+			this.tabsInTitlebarChanging
 			)
 			return;
 
-		var TabsOnTop = this.window.TabsOnTop;
+		this.tabsInTitlebarChanging = true;
+		// We have to do this with delay, because the tab bar is always on top
+		// for the toolbar customizing and returned to left or right after a delay.
+		setTimeout(this.updateTabsInTitlebarInternal.bind(this), 0);
+	},
+	updateTabsInTitlebarInternal : function TSTWindow_updateTabsInTitlebarInternal()
+	{
 		var TabsInTitlebar = this.window.TabsInTitlebar;
 		var isTopTabbar = this.browser.treeStyleTab.position == 'top';
 
-		this.tabsOnTopChangingByTST = true;
-
 		try {
-			if (TabsOnTop) {
-				let originalState = utils.getTreePref('tabsOnTop.originalState');
-				if (originalState === null) {
-					let current = prefs.getDefaultPref('browser.tabs.onTop') === null ?
-									TabsOnTop.enabled :
-									prefs.getPref('browser.tabs.onTop') ;
-					utils.setTreePref('tabsOnTop.originalState', originalState = current);
-				}
-
-				if (!isTopTabbar || !this.browser.treeStyleTab.fixed) {
-					if (TabsOnTop.enabled)
-						TabsOnTop.enabled = false;
-				}
-				else {
-					if (TabsOnTop.enabled != originalState)
-						TabsOnTop.enabled = originalState;
-					utils.clearTreePref('tabsOnTop.originalState');
-				}
-			}
 			if (TabsInTitlebar) {
-				let allowed = isTopTabbar && this.browser.treeStyleTab.fixed;
+				let menubar = this.window.document.getElementById('toolbar-menubar');
+				let allowed = (
+					(isTopTabbar && this.browser.treeStyleTab.fixed) ||
+					(!this.isMac && menubar.getAttribute('autohide') !== 'true')
+				);
 				if (
 					(this.window.TabsOnBottom && utils.getTreePref('compatibility.TabsOnBottom')) ||
 					('navbarontop' in this.window && utils.getTreePref('compatibility.NavbarOnTitlebar')) ||
 					('classicthemerestorerjs' in this.window && utils.getTreePref('compatibility.ClassicThemeRestorer'))
 					)
 					allowed = true;
-				TabsInTitlebar.allowedBy('TreeStyleTab-tabsOnTop', allowed);
+				TabsInTitlebar.allowedBy('TreeStyleTab-tabsInTitlebar', allowed);
 			}
 		}
 		finally {
-			this.tabsOnTopChangingByTST = false;
+			this.tabsInTitlebarChanging = false;
 		}
 	},
  
@@ -1163,17 +1238,17 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 			).booleanValue)
 			return;
 
-		this.window.setTimeout(function(aSelf) {
+		setTimeout((function() {
 			if ((!aPopup.boxObject.width && !aPopup.boxObject.height) ||
 				aPopup.boxObject.popupState == 'closed')
 				return;
 
 			var id = aPopup.id;
-			var item = id && aSelf.document.getElementById(id) ? id : aPopup ;
-			var index = aSelf._shownPopups.indexOf(item);
+			var item = id && this.document.getElementById(id) ? id : aPopup ;
+			var index = this._shownPopups.indexOf(item);
 			if (index < 0)
-				aSelf._shownPopups.push(item);
-		}, 10, this);
+				this._shownPopups.push(item);
+		}).bind(this), 10);
 	},
  
 	onPopupHidden : function TSTWindow_onPopupHidden(aPopup) 
@@ -1688,6 +1763,7 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 				}
 			};
 		this.window.addEventListener(this.kEVENT_TYPE_FOCUS_NEXT_TAB, listener, false);
+		ReferenceCounter.add('window,kEVENT_TYPE_FOCUS_NEXT_TAB,listener,false');
 		this._tabFocusAllowance.push(listener);
 	},
 	_tabFocusAllowance : [],
diff --git a/skin/classic/treestyletab/Linux-base.css b/skin/classic/treestyletab/Linux-base.css
index 31b67e7..925f386 100644
--- a/skin/classic/treestyletab/Linux-base.css
+++ b/skin/classic/treestyletab/Linux-base.css
@@ -53,3 +53,9 @@
   #TabsToolbar::after {
 	display: none;
 }
+
+/* cancel too much padding for the icon in the vertical tab bar */
+#main-window[treestyletab-mode="vertical"]
+  #alltabs-button > .toolbarbutton-icon {
+	padding: 3px 7px;
+}
diff --git a/skin/classic/treestyletab/square/tab-surface.css b/skin/classic/treestyletab/square/tab-surface.css
index b910e21..a9b3d0d 100644
--- a/skin/classic/treestyletab/square/tab-surface.css
+++ b/skin/classic/treestyletab/square/tab-surface.css
@@ -10,9 +10,9 @@
 }
 
 .tabbrowser-tabs:not([treestyletab-tabbar-position="top"])
-  .tabbrowser-tab
+  .tabbrowser-tab:not([titlechanged])
   :-moz-any(.tab-background:not([pinned]),
-            .tab-background:not([titlechanged])[pinned]) {
+            .tab-background[pinned]) {
 	background-color: -moz-dialog !important;
 	background-image: -moz-linear-gradient(
 	                    top, 
diff --git a/skin/classic/treestyletab/ui-base.css b/skin/classic/treestyletab/ui-base.css
index 7cb973b..600a32b 100644
--- a/skin/classic/treestyletab/ui-base.css
+++ b/skin/classic/treestyletab/ui-base.css
@@ -233,6 +233,22 @@ tabbrowser[treestyletab-drop-position="left"]:not([treestyletab-tabbar-position=
 	min-height: 22px;
 }
 
+.treestyletab-tabbar-toolbar[treestyletab-mode="vertical"]
+  toolbarbutton:not(.tab-close-button)
+  > .toolbarbutton-icon {
+	/**
+	 * This is required to block the tab bar to be shrunken.
+	 * See: https://github.com/piroor/treestyletab/issues/964#issuecomment-153781248
+	 */
+	max-width: none !important;
+	/**
+	 * But we still have to set maximum size of the icon
+	 * to shrink the size of high-res icons.
+	 * See: https://github.com/piroor/treestyletab/issues/964#issuecomment-153801249
+	 */
+	max-height: 16px;
+}
+
 /* transaprent tab bar */
 
 .tabbrowser-tabs[treestyletab-tabbar-autohide]
@@ -338,13 +354,22 @@ tabbrowser[treestyletab-tabbar-position="bottom"]
 }
 
 .tabbrowser-tabs[treestyletab-mode="vertical"]
-  .tab-content[pinned="true"] > image {
+  .tab-content[pinned="true"] > image:not(.tab-icon-overlay) {
 	height: 16px;
 	margin: 0;
 	padding: 0;
 	width: 16px;
 }
 
+/* overlay icon: because TST applies "min-height:2em" for tabs, overlay icons also should be rendered based on the "em" scale. */
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+  .tab-content[pinned="true"] > image.tab-icon-overlay {
+	height: 1em;
+	width: 1em;
+	margin-top: -0.7em !important;
+	-moz-margin-start: -1em !important;
+}
+
 /* disable highlighting of pinned tabs whici is not faviconized */
 
 .tabbrowser-tabs[treestyletab-mode="vertical"]
@@ -356,13 +381,6 @@ tabbrowser[treestyletab-tabbar-position="bottom"]
 	background-image: none;
 }
 
-/* overlay icon */
-.tabbrowser-tabs[treestyletab-mode="vertical"]
-  .tab-content[pinned="true"] > image.tab-icon-overlay {
-  margin-top: -14px !important;
-  -moz-margin-start: -8px !important;
-}
-
 
 /* notification of newly opened tabs in background */
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/tree-style-tab.git



More information about the Pkg-mozext-commits mailing list