Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / status_icons / status_tray_win.cc
index 8c66cd4..18830d3 100644 (file)
@@ -6,12 +6,15 @@
 
 #include <commctrl.h>
 
+#include "base/bind.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/thread.h"
 #include "base/win/wrapped_window_proc.h"
 #include "chrome/browser/ui/views/status_icons/status_icon_win.h"
+#include "chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h"
 #include "chrome/common/chrome_constants.h"
 #include "ui/gfx/screen.h"
 #include "ui/gfx/win/hwnd_util.h"
-#include "win8/util/win8_util.h"
 
 static const UINT kStatusIconMessage = WM_APP + 1;
 
@@ -24,6 +27,66 @@ UINT ReservedIconId(StatusTray::StatusIconType type) {
 }
 }  // namespace
 
+// Default implementation for StatusTrayStateChanger that communicates to
+// Exporer.exe via COM.  It spawns a background thread with a fresh COM
+// apartment and requests that the visibility be increased unless the user
+// has explicitly set the icon to be hidden.
+class StatusTrayStateChangerProxyImpl : public StatusTrayStateChangerProxy,
+                                        public base::NonThreadSafe {
+ public:
+  StatusTrayStateChangerProxyImpl()
+      : pending_requests_(0),
+        worker_thread_("StatusIconCOMWorkerThread"),
+        weak_factory_(this) {
+    worker_thread_.init_com_with_mta(false);
+  }
+
+  virtual void EnqueueChange(UINT icon_id, HWND window) OVERRIDE {
+    DCHECK(CalledOnValidThread());
+    if (pending_requests_ == 0)
+      worker_thread_.Start();
+
+    ++pending_requests_;
+    worker_thread_.message_loop_proxy()->PostTaskAndReply(
+        FROM_HERE,
+        base::Bind(
+            &StatusTrayStateChangerProxyImpl::EnqueueChangeOnWorkerThread,
+            icon_id,
+            window),
+        base::Bind(&StatusTrayStateChangerProxyImpl::ChangeDone,
+                   weak_factory_.GetWeakPtr()));
+  }
+
+ private:
+  // Must be called only on |worker_thread_|, to ensure the correct COM
+  // apartment.
+  static void EnqueueChangeOnWorkerThread(UINT icon_id, HWND window) {
+    // It appears that IUnknowns are coincidentally compatible with
+    // scoped_refptr.  Normally I wouldn't depend on that but it seems that
+    // base::win::IUnknownImpl itself depends on that coincidence so it's
+    // already being assumed elsewhere.
+    scoped_refptr<StatusTrayStateChangerWin> status_tray_state_changer(
+        new StatusTrayStateChangerWin(icon_id, window));
+    status_tray_state_changer->EnsureTrayIconVisible();
+  }
+
+  // Called on UI thread.
+  void ChangeDone() {
+    DCHECK(CalledOnValidThread());
+    DCHECK_GT(pending_requests_, 0);
+
+    if (--pending_requests_ == 0)
+      worker_thread_.Stop();
+  }
+
+ private:
+  int pending_requests_;
+  base::Thread worker_thread_;
+  base::WeakPtrFactory<StatusTrayStateChangerProxyImpl> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerProxyImpl);
+};
+
 StatusTrayWin::StatusTrayWin()
     : next_icon_id_(1),
       atom_(0),
@@ -54,6 +117,23 @@ StatusTrayWin::StatusTrayWin()
   gfx::SetWindowUserData(window_, this);
 }
 
+StatusTrayWin::~StatusTrayWin() {
+  if (window_)
+    DestroyWindow(window_);
+
+  if (atom_)
+    UnregisterClass(MAKEINTATOM(atom_), instance_);
+}
+
+void StatusTrayWin::UpdateIconVisibilityInBackground(
+    StatusIconWin* status_icon) {
+  if (!state_changer_proxy_.get())
+    state_changer_proxy_.reset(new StatusTrayStateChangerProxyImpl);
+
+  state_changer_proxy_->EnqueueChange(status_icon->icon_id(),
+                                      status_icon->window());
+}
+
 LRESULT CALLBACK StatusTrayWin::WndProcStatic(HWND hwnd,
                                               UINT message,
                                               WPARAM wparam,
@@ -117,14 +197,6 @@ LRESULT CALLBACK StatusTrayWin::WndProc(HWND hwnd,
   return ::DefWindowProc(hwnd, message, wparam, lparam);
 }
 
-StatusTrayWin::~StatusTrayWin() {
-  if (window_)
-    DestroyWindow(window_);
-
-  if (atom_)
-    UnregisterClass(MAKEINTATOM(atom_), instance_);
-}
-
 StatusIcon* StatusTrayWin::CreatePlatformStatusIcon(
     StatusTray::StatusIconType type,
     const gfx::ImageSkia& image,
@@ -135,11 +207,8 @@ StatusIcon* StatusTrayWin::CreatePlatformStatusIcon(
   else
     next_icon_id = ReservedIconId(type);
 
-  StatusIcon* icon = NULL;
-  if (win8::IsSingleWindowMetroMode())
-    icon = new StatusIconMetro(next_icon_id);
-  else
-    icon = new StatusIconWin(next_icon_id, window_, kStatusIconMessage);
+  StatusIcon* icon =
+      new StatusIconWin(this, next_icon_id, window_, kStatusIconMessage);
 
   icon->SetImage(image);
   icon->SetToolTip(tool_tip);
@@ -151,6 +220,11 @@ UINT StatusTrayWin::NextIconId() {
   return kBaseIconId + static_cast<UINT>(NAMED_STATUS_ICON_COUNT) + icon_id;
 }
 
+void StatusTrayWin::SetStatusTrayStateChangerProxyForTest(
+    scoped_ptr<StatusTrayStateChangerProxy> proxy) {
+  state_changer_proxy_ = proxy.Pass();
+}
+
 StatusTray* StatusTray::Create() {
   return new StatusTrayWin();
 }