普通文本  |  89行  |  2.55 KB

// Copyright 2013 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 "ui/views/win/appbar.h"

#include <shellapi.h>

#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/threading/worker_pool.h"
#include "base/win/scoped_com_initializer.h"
#include "ui/views/widget/monitor_win.h"

namespace views {

namespace {

void GetEdgesOnWorkerThread(HMONITOR monitor, int* edge) {
  base::win::ScopedCOMInitializer com_initializer;
  *edge = 0;
  if (GetTopmostAutoHideTaskbarForEdge(ABE_LEFT, monitor))
    *edge = Appbar::EDGE_LEFT;
  if (GetTopmostAutoHideTaskbarForEdge(ABE_TOP, monitor))
    *edge = Appbar::EDGE_TOP;
  if (GetTopmostAutoHideTaskbarForEdge(ABE_RIGHT, monitor))
    *edge = Appbar::EDGE_RIGHT;
  if (GetTopmostAutoHideTaskbarForEdge(ABE_BOTTOM, monitor))
    *edge = Appbar::EDGE_BOTTOM;
}

}

// static
Appbar* Appbar::instance() {
  static Appbar* appbar = NULL;
  if (!appbar)
    appbar = new Appbar();
  return appbar;
}

int Appbar::GetAutohideEdges(HMONITOR monitor, const base::Closure& callback) {
  // Initialize the map with EDGE_BOTTOM. This is important, as if we return an
  // initial value of 0 (no auto-hide edges) then we'll go fullscreen and
  // windows will automatically remove WS_EX_TOPMOST from the appbar resulting
  // in us thinking there is no auto-hide edges. By returning at least one edge
  // we don't initially go fullscreen until we figure out the real auto-hide
  // edges.
  if (edge_map_.find(monitor) == edge_map_.end())
    edge_map_[monitor] = Appbar::EDGE_BOTTOM;
  if (!in_callback_) {
    int* edge = new int;
    base::WorkerPool::PostTaskAndReply(
        FROM_HERE,
        base::Bind(&GetEdgesOnWorkerThread,
                   monitor,
                   base::Unretained(edge)),
        base::Bind(&Appbar::OnGotEdges,
                   weak_factory_.GetWeakPtr(),
                   callback,
                   monitor,
                   edge_map_[monitor],
                   base::Owned(edge)),
        false);
  }
  return edge_map_[monitor];
}

Appbar::Appbar() : weak_factory_(this), in_callback_(false) {
}

Appbar::~Appbar() {
}

void Appbar::OnGotEdges(const base::Closure& callback,
                        HMONITOR monitor,
                        int returned_edges,
                        int* edges) {
  edge_map_[monitor] = *edges;
  if (returned_edges == *edges)
    return;

  base::AutoReset<bool> in_callback_setter(&in_callback_, true);
  callback.Run();
}

}  // namespace views