summaryrefslogtreecommitdiffstats
path: root/ceee/ie/plugin/bho/tool_band_visibility.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ceee/ie/plugin/bho/tool_band_visibility.cc')
-rw-r--r--ceee/ie/plugin/bho/tool_band_visibility.cc179
1 files changed, 179 insertions, 0 deletions
diff --git a/ceee/ie/plugin/bho/tool_band_visibility.cc b/ceee/ie/plugin/bho/tool_band_visibility.cc
new file mode 100644
index 0000000..8952457
--- /dev/null
+++ b/ceee/ie/plugin/bho/tool_band_visibility.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ceee/ie/plugin/bho/tool_band_visibility.h"
+
+#include "base/logging.h"
+#include "ceee/ie/common/ie_tab_interfaces.h"
+#include "ceee/ie/common/ceee_module_util.h"
+#include "ceee/ie/plugin/toolband/tool_band.h"
+
+// The ToolBandVisibility class allows us to recover from a number of
+// features of IE that can cause our toolband to become invisible
+// unexpectedly.
+
+// A brief discussion of toolband visibility in IE.
+//
+// See MS knowledge base article Q219427 for more detail.
+//
+// IE does some interesting tricks to cache toolband layout information. One
+// side effect of this is that sometimes it can get confused about whether a
+// toolband should be shown or not.
+//
+// In theory all that is needed to recover from this is a call to
+// IWebBrowser2::ShowBrowserBar. Unfortunately, there are some
+// gotchas.
+// It's not easy to tell when IE has refused to display your
+// toolband. The only way to be sure is to either call
+// ShowBrowserBar on every startup or wait for some reasonable
+// time to see if IE showed the toolband and then kick it if it
+// didn't.
+// In IE6, a single call to ShowBrowserBar is often not enough to
+// unhide a hidden toolband. It's sometimes necessary to call
+// ShowBrowserBar THREE times (show, then hide, then show) to get
+// things into a sane state.
+// TODO(cindylau@chromium.org): In IE6, just calling ShowBrowserBar
+// will usually cause IE to scrunch our toolband up at the end of
+// a line instead of giving it its own line. We can combat this
+// by requesting to be shown on our own line, but if we do that
+// in all cases we'll anger users who WANT our toolband to share
+// a line with others.
+// Some other toolbands (notably SnagIt versions 6 and 7) will
+// cause toolbands to get hidden when opening a new tab in IE7.
+// Visibility must be checked on every new tab and window to be
+// sure.
+// Calls to ShowBrowserBar are slow and we should avoid them
+// whenever possible.
+// Calls to ShowBrowserBar should be made from the same UI thread
+// responsible for the browser object we use to unhide the
+// toolband. Failure to do this can cause the toolband to
+// believe it belongs to a different thread than it does.
+// TODO(cindylau@chromium.org): IE tracks layout information in the
+// registry. When toolbands are added or removed the installing
+// toolband MUST clear the registry (badness, including possible
+// crashes in IE will result if not). When this layout
+// information is cleared all third party toolbands are hidden.
+
+// This code attempts to address all of these issues.
+// The core is the VisibilityUtil class.
+// When VisibilityUtil::CheckVisibility is called it checks for common
+// indicators that a toolband is hidden. If it sees a smoking gun
+// it unhides the toolband. Otherwise it creates a notification window and
+// a timer. If a toolband doesn't report itself as active for a particular
+// browser window before the timer fires it unhides the toolband.
+
+namespace {
+const int kVisibilityTimerId = 1;
+const DWORD kVisibilityCheckDelay = 2000; // 2 seconds.
+} // anonymous namespace
+
+std::set<IUnknown*> ToolBandVisibility::visibility_set_;
+CComAutoCriticalSection ToolBandVisibility::visibility_set_crit_;
+
+ToolBandVisibility::ToolBandVisibility()
+ : web_browser_(NULL) {
+}
+
+ToolBandVisibility::~ToolBandVisibility() {
+ DCHECK(m_hWnd == NULL);
+}
+
+void ToolBandVisibility::ReportToolBandVisible(IWebBrowser2* web_browser) {
+ DCHECK(web_browser);
+ CComQIPtr<IUnknown, &IID_IUnknown> browser_identity(web_browser);
+ DCHECK(browser_identity != NULL);
+ if (browser_identity == NULL)
+ return;
+ CComCritSecLock<CComAutoCriticalSection> lock(visibility_set_crit_);
+ visibility_set_.insert(browser_identity);
+}
+
+bool ToolBandVisibility::IsToolBandVisible(IWebBrowser2* web_browser) {
+ DCHECK(web_browser);
+ CComQIPtr<IUnknown, &IID_IUnknown> browser_identity(web_browser);
+ DCHECK(browser_identity != NULL);
+ if (browser_identity == NULL)
+ return false;
+ CComCritSecLock<CComAutoCriticalSection> lock(visibility_set_crit_);
+ return visibility_set_.count(browser_identity) != 0;
+}
+
+void ToolBandVisibility::ClearCachedVisibility(IWebBrowser2* web_browser) {
+ CComCritSecLock<CComAutoCriticalSection> lock(visibility_set_crit_);
+ if (web_browser) {
+ CComQIPtr<IUnknown, &IID_IUnknown> browser_identity(web_browser);
+ DCHECK(browser_identity != NULL);
+ if (browser_identity == NULL)
+ return;
+ visibility_set_.erase(browser_identity);
+ } else {
+ visibility_set_.clear();
+ }
+}
+
+void ToolBandVisibility::CheckToolBandVisibility(IWebBrowser2* web_browser) {
+ DCHECK(web_browser);
+ web_browser_ = web_browser;
+
+ if (!ceee_module_util::GetOptionToolbandIsHidden() &&
+ CreateNotificationWindow()) {
+ SetWindowTimer(kVisibilityTimerId, kVisibilityCheckDelay);
+ }
+}
+
+void ToolBandVisibility::TearDown() {
+ if (web_browser_ != NULL) {
+ ClearCachedVisibility(web_browser_);
+ }
+ if (m_hWnd != NULL) {
+ CloseNotificationWindow();
+ }
+}
+
+bool ToolBandVisibility::CreateNotificationWindow() {
+ return Create(HWND_MESSAGE) != NULL;
+}
+
+void ToolBandVisibility::CloseNotificationWindow() {
+ DestroyWindow();
+}
+
+void ToolBandVisibility::SetWindowTimer(UINT timer_id, UINT delay) {
+ SetTimer(timer_id, delay, NULL);
+}
+
+void ToolBandVisibility::KillWindowTimer(UINT timer_id) {
+ KillTimer(timer_id);
+}
+
+void ToolBandVisibility::OnTimer(UINT_PTR nIDEvent) {
+ DCHECK(nIDEvent == kVisibilityTimerId);
+ KillWindowTimer(nIDEvent);
+
+ if (!IsToolBandVisible(web_browser_)) {
+ UnhideToolBand();
+ }
+ ClearCachedVisibility(web_browser_);
+ CloseNotificationWindow();
+}
+
+void ToolBandVisibility::UnhideToolBand() {
+ // Ignore ShowDW calls that are triggered by our calls here to
+ // ShowBrowserBar.
+ ceee_module_util::SetIgnoreShowDWChanges(true);
+ CComVariant toolband_class(CLSID_ToolBand);
+ CComVariant show(false);
+ CComVariant empty;
+ show = true;
+ web_browser_->ShowBrowserBar(&toolband_class, &show, &empty);
+
+ // Force IE to ignore bad caching. This is a problem generally before IE7,
+ // and at least sometimes even in IE7 (bb1291042).
+ show = false;
+ web_browser_->ShowBrowserBar(&toolband_class, &show, &empty);
+ show = true;
+ web_browser_->ShowBrowserBar(&toolband_class, &show, &empty);
+
+ ceee_module_util::SetIgnoreShowDWChanges(false);
+}