<commit_before>/*
Copyright 2015 Adam Grandquist

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */
/**
 * @author Adam Grandquist
 * @copyright Apache
 */

#ifndef REQL_REQL_SOCKET_HPP_
#define REQL_REQL_SOCKET_HPP_

#include <atomic>
#include <cerrno>
#include <condition_variable>
#include <iterator>
#include <list>
#include <memory>
#include <thread>

#ifdef __MINGW32__
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#else
#include <netdb.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#endif

namespace _ReQL {

template <class elem_t>
class Pipe_t;

template <class elem_t>
class Observer_t : std::iterator<std::input_iterator_tag, elem_t> {
public:
  bool operator ==(const Observer_t &other) const {
    return this == &other;
  }

  bool operator !=(const Observer_t &other) const {
    return this != &other;
  }

  Observer_t &operator ++() {
    std::unique_lock<std::mutex> lock(p_mutex);
    wait(lock);
    if (p_pipe) {
      p_pos = p_pipe->p_list.erase(p_pos);
    } else {
    }
    return *this;
  }

  elem_t &operator *() {
    std::unique_lock<std::mutex> lock(p_mutex);
    wait(lock);
    return *p_pos;
  }

private:
  friend class Pipe_t<elem_t>;

  Observer_t(Pipe_t<elem_t> *pipe) : p_pipe(pipe) {}

  void wait(std::unique_lock<std::mutex> &lock) {
    p_cond.wait(lock, [this] { return (!p_pipe) || p_pos != p_list.cend(); });
  }

  std::condition_variable p_cond;
  std::mutex p_mutex;
  typename std::list<elem_t>::iterator p_pos;
  Pipe_t<elem_t> *p_pipe;
};

template <class elem_t>
class Pipe_t {
  bool operator ==(const Pipe_t &other) const {
    return this == &other;
  }

  bool operator !=(const Pipe_t &other) const {
    return this != &other;
  }

  void push(elem_t &&elem) {
    std::unique_lock<std::mutex> lock(p_mutex);
    p_cond.notify_all();
    p_list.push_back(elem);
  }

  void close() {
    std::unique_lock<std::mutex> lock(p_mutex);
    p_observer->p_pipe = nullptr;
    p_observer->p_cond.notify_all();
  }

private:
  std::list<elem_t> p_list;
  Observer_t<elem_t> *p_observer;
};

template <class socket_e>
class Socket_t {
public:
  template <class addr_t, class port_t>
  static int _connect(const addr_t &addr, const port_t &port) {
    struct addrinfo hints;
    struct addrinfo *result, *rp;

    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = 0;
    hints.ai_protocol = IPPROTO_TCP;

    int sts = 0;

    if ((sts = getaddrinfo(addr.c_str(), port.c_str(), &hints, &result)) != 0) {
      throw socket_e(gai_strerror(sts));
    }

    int sock = -1;

    for (rp = result; rp != nullptr; rp = rp->ai_next) {
      sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);

      if (sock == -1) continue;

      if (::connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break;

      ::close(sock);
    }

    freeaddrinfo(result);

    if (rp) {
      return sock;
    }

    throw socket_e("");  // TODO
  }

  template <class addr_t, class port_t>
  void connect(const addr_t &addr, const port_t &port) {
    p_sock = std::make_shared<int>(_connect(addr, port));
  }

  void disconnect() {
    p_sock.reset();
  }

  bool connected() const {
    return p_sock ? true : false;
  }

  std::string read() {
    int sock = load();
    wait_read();
    ssize_t size = 0;
    socklen_t opt_len = sizeof(ssize_t);
    auto sts = getsockopt(sock, SOL_SOCKET, SO_NREAD, &size, &opt_len);
    if (sts < 0) {
      switch (errno) {
        case EBADF:
        case EFAULT:
        case EINVAL:
        case ENOBUFS:
        case ENOMEM:
        case ENOPROTOOPT:
        case ENOTSOCK: {
          throw socket_e("");  // TODO
        }
        default: {
          throw socket_e("");  // TODO
        }
      }
      throw std::exception();
    }
    std::unique_ptr<char> buffer(new char[static_cast<size_t>(size)]);
    size = recvfrom(sock, buffer.get(), static_cast<size_t>(size), MSG_WAITALL, nullptr, nullptr);
    if (size == 0) {
      throw socket_e("");  // TODO
    } else if (size < 0) {
      switch (errno) {
        case EAGAIN: {
          return std::string();
        }
        case EBADF:
        case ECONNRESET:
        case EFAULT:
        case EINTR:
        case EINVAL:
        case ENOBUFS:
        case ENOTCONN:
        case ENOTSOCK:
        case EOPNOTSUPP:
        case ETIMEDOUT: {
          throw socket_e("");  // TODO
        }
        default: {
          throw socket_e("");  // TODO
        }
      }
      throw std::exception();
    }
    return std::string(buffer.get(), static_cast<size_t>(size));
  }

  void write(const char *out, const size_t size) {
    int sock = load();
    wait_write();
    send(sock, out, size, 0);
  }

private:
  bool poll(bool read = true) {
    int sock = load();
    timeval to = {0, 0};
    fd_set set;
    FD_ZERO(&set);
    FD_SET(sock, &set);
    auto sts = ::select(sock + 1,
                        read ? &set : nullptr,
                        read ? nullptr : &set,
                        &set, &to);
    if (sts == 0) {
      return false;
    } else if (sts < 0) {
      switch (errno) {
        case EAGAIN:
        case EBADF:
        case EINTR:
        case EINVAL:{
          throw socket_e("");  // TODO
        }
        default: {
          throw socket_e("");  // TODO
        }
      }
      throw std::exception();
    }
    return true;
  }

  void wait_read() {
    while (!poll()) {
      std::this_thread::yield();
    }
  }

  void wait_write() {
    while (!poll(false)) {
      std::this_thread::yield();
    }
  }

  int load() {
    int sock = *p_sock;
    if (sock) {
      return sock;
    }
    throw socket_e("");  // TODO
  }

  static void deleter(int *sock) {
    ::close(*sock);
    delete sock;
  }

  std::shared_ptr<int> p_sock;
};

}  // namespace _ReQL

#endif  // REQL_REQL_SOCKET_HPP_
<commit_msg>Separate pipe interface into three classes.<commit_after>/*
Copyright 2015 Adam Grandquist

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */
/**
 * @author Adam Grandquist
 * @copyright Apache
 */

#ifndef REQL_REQL_SOCKET_HPP_
#define REQL_REQL_SOCKET_HPP_

#include <atomic>
#include <cerrno>
#include <condition_variable>
#include <iterator>
#include <list>
#include <memory>
#include <thread>

#ifdef __MINGW32__
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#else
#include <netdb.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#endif

namespace _ReQL {

template <class elem_t>
class Pipe_t;

template <class elem_t>
class Producer_t {
public:
  bool operator ==(const Producer_t &other) const {
    return this == &other;
  }

  bool operator !=(const Producer_t &other) const {
    return this != &other;
  }

  void push(elem_t &&elem) {
    auto pipe = p_pipe;
    if (!pipe) {
      return;
    }
    std::unique_lock<std::mutex> lock(pipe->p_mutex);
    if (p_pipe != pipe) {
      return;
    }
    pipe->p_cond.notify_all();
    pipe->p_list.push_back(elem);
  }

  void close() {
    auto pipe = p_pipe;
    if (!pipe) {
      return;
    }
    std::unique_lock<std::mutex> lock(pipe->p_mutex);
    if (p_pipe != pipe) {
      return;
    }
    pipe->p_cond.notify_all();
    pipe->close();
    p_pipe = nullptr;
  }

private:
  friend class Pipe_t<elem_t>;

  Producer_t(Pipe_t<elem_t> *pipe) : p_pipe(pipe) {}

  Pipe_t<elem_t> *p_pipe;
};

template <class elem_t>
class Observer_t;

template <class elem_t>
class Pipe_t {
public:
  bool operator ==(const Pipe_t &other) const {
    return this == &other;
  }

  bool operator !=(const Pipe_t &other) const {
    return this != &other;
  }

private:
  friend class Observer_t<elem_t>;
  friend class Producer_t<elem_t>;

  Pipe_t(Observer_t<elem_t> *observer) : p_observer(observer) {}

  void close() {}

  std::condition_variable p_cond;
  std::list<elem_t> p_list;
  std::mutex p_mutex;
  Observer_t<elem_t> *p_observer;
  Producer_t<elem_t> p_producer;
};

template <class elem_t>
class Observer_t : std::iterator<std::input_iterator_tag, elem_t> {
public:
  bool operator ==(const Observer_t &other) const {
    return this == &other;
  }

  bool operator !=(const Observer_t &other) const {
    return this != &other;
  }

  Observer_t &operator ++() {
    std::unique_lock<std::mutex> lock(p_pipe.p_mutex);
    wait(lock);
    p_pipe.p_list.erase();
    return *this;
  }

  elem_t &operator *() {
    std::unique_lock<std::mutex> lock(p_mutex);
    wait(lock);
    return *p_pos;
  }

private:
  friend class Pipe_t<elem_t>;

  void wait(std::unique_lock<std::mutex> &lock) {
    p_cond.wait(lock, [this] { return (!p_pipe) || p_pos != p_list.cend(); });
  }

  Pipe_t<elem_t> p_pipe;
};

template <class socket_e>
class Socket_t {
public:
  template <class addr_t, class port_t>
  static int _connect(const addr_t &addr, const port_t &port) {
    struct addrinfo hints;
    struct addrinfo *result, *rp;

    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = 0;
    hints.ai_protocol = IPPROTO_TCP;

    int sts = 0;

    if ((sts = getaddrinfo(addr.c_str(), port.c_str(), &hints, &result)) != 0) {
      throw socket_e(gai_strerror(sts));
    }

    int sock = -1;

    for (rp = result; rp != nullptr; rp = rp->ai_next) {
      sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);

      if (sock == -1) continue;

      if (::connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break;

      ::close(sock);
    }

    freeaddrinfo(result);

    if (rp) {
      return sock;
    }

    throw socket_e("");  // TODO
  }

  template <class addr_t, class port_t>
  void connect(const addr_t &addr, const port_t &port) {
    p_sock = std::make_shared<int>(_connect(addr, port));
  }

  void disconnect() {
    p_sock.reset();
  }

  bool connected() const {
    return p_sock ? true : false;
  }

  std::string read() {
    int sock = load();
    wait_read();
    ssize_t size = 0;
    socklen_t opt_len = sizeof(ssize_t);
    auto sts = getsockopt(sock, SOL_SOCKET, SO_NREAD, &size, &opt_len);
    if (sts < 0) {
      switch (errno) {
        case EBADF:
        case EFAULT:
        case EINVAL:
        case ENOBUFS:
        case ENOMEM:
        case ENOPROTOOPT:
        case ENOTSOCK: {
          throw socket_e("");  // TODO
        }
        default: {
          throw socket_e("");  // TODO
        }
      }
      throw std::exception();
    }
    std::unique_ptr<char> buffer(new char[static_cast<size_t>(size)]);
    size = recvfrom(sock, buffer.get(), static_cast<size_t>(size), MSG_WAITALL, nullptr, nullptr);
    if (size == 0) {
      throw socket_e("");  // TODO
    } else if (size < 0) {
      switch (errno) {
        case EAGAIN: {
          return std::string();
        }
        case EBADF:
        case ECONNRESET:
        case EFAULT:
        case EINTR:
        case EINVAL:
        case ENOBUFS:
        case ENOTCONN:
        case ENOTSOCK:
        case EOPNOTSUPP:
        case ETIMEDOUT: {
          throw socket_e("");  // TODO
        }
        default: {
          throw socket_e("");  // TODO
        }
      }
      throw std::exception();
    }
    return std::string(buffer.get(), static_cast<size_t>(size));
  }

  void write(const char *out, const size_t size) {
    int sock = load();
    wait_write();
    send(sock, out, size, 0);
  }

private:
  bool poll(bool read = true) {
    int sock = load();
    timeval to = {0, 0};
    fd_set set;
    FD_ZERO(&set);
    FD_SET(sock, &set);
    auto sts = ::select(sock + 1,
                        read ? &set : nullptr,
                        read ? nullptr : &set,
                        &set, &to);
    if (sts == 0) {
      return false;
    } else if (sts < 0) {
      switch (errno) {
        case EAGAIN:
        case EBADF:
        case EINTR:
        case EINVAL:{
          throw socket_e("");  // TODO
        }
        default: {
          throw socket_e("");  // TODO
        }
      }
      throw std::exception();
    }
    return true;
  }

  void wait_read() {
    while (!poll()) {
      std::this_thread::yield();
    }
  }

  void wait_write() {
    while (!poll(false)) {
      std::this_thread::yield();
    }
  }

  int load() {
    int sock = *p_sock;
    if (sock) {
      return sock;
    }
    throw socket_e("");  // TODO
  }

  static void deleter(int *sock) {
    ::close(*sock);
    delete sock;
  }

  std::shared_ptr<int> p_sock;
};

}  // namespace _ReQL

#endif  // REQL_REQL_SOCKET_HPP_
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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 "base/ref_counted.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/test_extension_loader.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/site_instance.h"
#include "chrome/browser/views/extensions/extension_shelf.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_error_reporter.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

namespace {

// How long to wait for the extension to put up a javascript alert before giving
// up.
const int kAlertTimeoutMs = 20000;

// The extensions we're using as our test case.
const char* kGoodExtension1Id = "00123456789abcdef0123456789abcdef0123456";
const char* kGoodCrxId        = "00123456789abcdef0123456789abcdef0123456";

};  // namespace

// This class starts up an extension process and waits until it tries to put
// up a javascript alert.
class MockExtensionHost : public ExtensionHost {
 public:
  MockExtensionHost(Extension* extension, const GURL& url,
                    SiteInstance* instance)
      : ExtensionHost(extension, instance, url, NULL),
        got_message_(false) {
    CreateRenderView(NULL);
    MessageLoop::current()->PostDelayedTask(FROM_HERE,
        new MessageLoop::QuitTask, kAlertTimeoutMs);
    ui_test_utils::RunMessageLoop();
  }

  virtual ExtensionFunctionDispatcher* CreateExtensionFunctionDispatcher(
      RenderViewHost* render_view_host) {
    NOTREACHED();
    return NULL;
  }

  bool got_message() { return got_message_; }
 private:
  virtual void RunJavaScriptMessage(
      const std::wstring& message,
      const std::wstring& default_prompt,
      const GURL& frame_url,
      const int flags,
      IPC::Message* reply_msg,
      bool* did_suppress_message) {
    got_message_ = true;
    MessageLoopForUI::current()->Quit();

    // Call super, otherwise we'll leak reply_msg.
    ExtensionHost::RunJavaScriptMessage(
        message, default_prompt, frame_url, flags,
        reply_msg, did_suppress_message);
  }

  bool got_message_;
};

class ExtensionViewTest : public InProcessBrowserTest {
 public:
  virtual void SetUp() {
    // Initialize the error reporter here, otherwise BrowserMain will create it
    // with the wrong MessageLoop.
    ExtensionErrorReporter::Init(false);

    // Use single-process in an attempt to speed it up and make it less flaky.
    //EnableSingleProcess();

    InProcessBrowserTest::SetUp();
  }
  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitch(switches::kEnableExtensions);
  }
};

// Tests that ExtensionView starts an extension process and runs the script
// contained in the extension's toolstrip.
IN_PROC_BROWSER_TEST_F(ExtensionViewTest, Toolstrip) {
  // Get the path to our extension.
  FilePath path;
  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
  path = path.AppendASCII("extensions").
      AppendASCII("good").AppendASCII("extension1").AppendASCII("1");
  ASSERT_TRUE(file_util::DirectoryExists(path));  // sanity check

  // Wait for the extension to load and grab a pointer to it.
  TestExtensionLoader loader(browser()->profile());
  Extension* extension = loader.Load(kGoodExtension1Id, path);
  ASSERT_TRUE(extension);
  GURL url = Extension::GetResourceURL(extension->url(), "toolstrip1.html");

  // Start the extension process and wait for it to show a javascript alert.
  MockExtensionHost host(extension, url,
      browser()->profile()->GetExtensionProcessManager()->
          GetSiteInstanceForURL(url));
  EXPECT_TRUE(host.got_message());
}

// Tests that the ExtensionShelf initializes properly, notices that
// an extension loaded and has a view available, and then sets that up
// properly.
IN_PROC_BROWSER_TEST_F(ExtensionViewTest, Shelf) {
  // When initialized, there are no extension views and the preferred height
  // should be zero.
  scoped_ptr<ExtensionShelf> shelf(new ExtensionShelf(browser()));
  EXPECT_EQ(shelf->GetChildViewCount(), 0);
  EXPECT_EQ(shelf->GetPreferredSize().height(), 0);

  // Get the path to our extension.
  FilePath path;
  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
  path = path.AppendASCII("extensions").
      AppendASCII("good").AppendASCII("extension1").AppendASCII("1");
  ASSERT_TRUE(file_util::DirectoryExists(path));  // sanity check

  // Wait for the extension to load and grab a pointer to it.
  TestExtensionLoader loader(browser()->profile());
  Extension* extension = loader.Load(kGoodExtension1Id, path);
  ASSERT_TRUE(extension);

  // There should now be two extension views and preferred height of the view
  // should be non-zero.
  EXPECT_EQ(shelf->GetChildViewCount(), 2);
  EXPECT_NE(shelf->GetPreferredSize().height(), 0);
}

// Tests that installing and uninstalling extensions don't crash with an
// incognito window open.
IN_PROC_BROWSER_TEST_F(ExtensionViewTest, Incognito) {
  // Open an incognito window to the extensions management page.  We just
  // want to make sure that we don't crash while playing with extensions when
  // this guy is around.
  Browser::OpenURLOffTheRecord(browser()->profile(),
                               GURL(chrome::kChromeUIExtensionsURL));

  // Get the path to our extension.
  FilePath path;
  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
  path = path.AppendASCII("extensions").AppendASCII("good.crx");
  ASSERT_TRUE(file_util::PathExists(path));  // sanity check

  // Wait for the extension to load and grab a pointer to it.
  TestExtensionLoader loader(browser()->profile());
  Extension* extension = loader.Install(kGoodCrxId, path);
  ASSERT_TRUE(extension);

  // TODO(mpcomplete): wait for uninstall to complete?
  browser()->profile()->GetExtensionsService()->UninstallExtension(kGoodCrxId);
}
<commit_msg>Disabling a test (bug filed) that is crashing (I am not sure what the correct fix is).<commit_after>// Copyright (c) 2006-2008 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 "base/ref_counted.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/test_extension_loader.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/site_instance.h"
#include "chrome/browser/views/extensions/extension_shelf.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_error_reporter.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

namespace {

// How long to wait for the extension to put up a javascript alert before giving
// up.
const int kAlertTimeoutMs = 20000;

// The extensions we're using as our test case.
const char* kGoodExtension1Id = "00123456789abcdef0123456789abcdef0123456";
const char* kGoodCrxId        = "00123456789abcdef0123456789abcdef0123456";

};  // namespace

// This class starts up an extension process and waits until it tries to put
// up a javascript alert.
class MockExtensionHost : public ExtensionHost {
 public:
  MockExtensionHost(Extension* extension, const GURL& url,
                    SiteInstance* instance)
      : ExtensionHost(extension, instance, url, NULL),
        got_message_(false) {
    CreateRenderView(NULL);
    MessageLoop::current()->PostDelayedTask(FROM_HERE,
        new MessageLoop::QuitTask, kAlertTimeoutMs);
    ui_test_utils::RunMessageLoop();
  }

  virtual ExtensionFunctionDispatcher* CreateExtensionFunctionDispatcher(
      RenderViewHost* render_view_host) {
    NOTREACHED();
    return NULL;
  }

  bool got_message() { return got_message_; }
 private:
  virtual void RunJavaScriptMessage(
      const std::wstring& message,
      const std::wstring& default_prompt,
      const GURL& frame_url,
      const int flags,
      IPC::Message* reply_msg,
      bool* did_suppress_message) {
    got_message_ = true;
    MessageLoopForUI::current()->Quit();

    // Call super, otherwise we'll leak reply_msg.
    ExtensionHost::RunJavaScriptMessage(
        message, default_prompt, frame_url, flags,
        reply_msg, did_suppress_message);
  }

  bool got_message_;
};

class ExtensionViewTest : public InProcessBrowserTest {
 public:
  virtual void SetUp() {
    // Initialize the error reporter here, otherwise BrowserMain will create it
    // with the wrong MessageLoop.
    ExtensionErrorReporter::Init(false);

    // Use single-process in an attempt to speed it up and make it less flaky.
    //EnableSingleProcess();

    InProcessBrowserTest::SetUp();
  }
  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitch(switches::kEnableExtensions);
  }
};

// Tests that ExtensionView starts an extension process and runs the script
// contained in the extension's toolstrip.
IN_PROC_BROWSER_TEST_F(ExtensionViewTest, Toolstrip) {
  // Get the path to our extension.
  FilePath path;
  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
  path = path.AppendASCII("extensions").
      AppendASCII("good").AppendASCII("extension1").AppendASCII("1");
  ASSERT_TRUE(file_util::DirectoryExists(path));  // sanity check

  // Wait for the extension to load and grab a pointer to it.
  TestExtensionLoader loader(browser()->profile());
  Extension* extension = loader.Load(kGoodExtension1Id, path);
  ASSERT_TRUE(extension);
  GURL url = Extension::GetResourceURL(extension->url(), "toolstrip1.html");

  // Start the extension process and wait for it to show a javascript alert.
  MockExtensionHost host(extension, url,
      browser()->profile()->GetExtensionProcessManager()->
          GetSiteInstanceForURL(url));
  EXPECT_TRUE(host.got_message());
}

// Tests that the ExtensionShelf initializes properly, notices that
// an extension loaded and has a view available, and then sets that up
// properly.
IN_PROC_BROWSER_TEST_F(ExtensionViewTest, Shelf) {
  // When initialized, there are no extension views and the preferred height
  // should be zero.
  scoped_ptr<ExtensionShelf> shelf(new ExtensionShelf(browser()));
  EXPECT_EQ(shelf->GetChildViewCount(), 0);
  EXPECT_EQ(shelf->GetPreferredSize().height(), 0);

  // Get the path to our extension.
  FilePath path;
  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
  path = path.AppendASCII("extensions").
      AppendASCII("good").AppendASCII("extension1").AppendASCII("1");
  ASSERT_TRUE(file_util::DirectoryExists(path));  // sanity check

  // Wait for the extension to load and grab a pointer to it.
  TestExtensionLoader loader(browser()->profile());
  Extension* extension = loader.Load(kGoodExtension1Id, path);
  ASSERT_TRUE(extension);

  // There should now be two extension views and preferred height of the view
  // should be non-zero.
  EXPECT_EQ(shelf->GetChildViewCount(), 2);
  EXPECT_NE(shelf->GetPreferredSize().height(), 0);
}

// Tests that installing and uninstalling extensions don't crash with an
// incognito window open.
// TODO(mpcomplete): http://crbug.com/14947 disabled because it crashes.
IN_PROC_BROWSER_TEST_F(ExtensionViewTest, DISABLED_Incognito) {
  // Open an incognito window to the extensions management page.  We just
  // want to make sure that we don't crash while playing with extensions when
  // this guy is around.
  Browser::OpenURLOffTheRecord(browser()->profile(),
                               GURL(chrome::kChromeUIExtensionsURL));

  // Get the path to our extension.
  FilePath path;
  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
  path = path.AppendASCII("extensions").AppendASCII("good.crx");
  ASSERT_TRUE(file_util::PathExists(path));  // sanity check

  // Wait for the extension to load and grab a pointer to it.
  TestExtensionLoader loader(browser()->profile());
  Extension* extension = loader.Install(kGoodCrxId, path);
  ASSERT_TRUE(extension);

  // TODO(mpcomplete): wait for uninstall to complete?
  browser()->profile()->GetExtensionsService()->UninstallExtension(kGoodCrxId);
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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 "chrome/browser/extensions/extension.h"

#include "base/logging.h"
#include "base/string_util.h"

const FilePath::CharType* Extension::kManifestFilename =
    FILE_PATH_LITERAL("manifest");

const wchar_t* Extension::kFormatVersionKey = L"format_version";
const wchar_t* Extension::kIdKey = L"id";
const wchar_t* Extension::kNameKey = L"name";
const wchar_t* Extension::kDescriptionKey = L"description";
const wchar_t* Extension::kContentScriptsKey = L"content_scripts";

const wchar_t* Extension::kInvalidManifestError =
    L"Manifest is missing or invalid.";
const wchar_t* Extension::kInvalidFormatVersionError =
    StringPrintf(L"Required key '%ls' is missing or invalid",
                 kFormatVersionKey).c_str();
const wchar_t* Extension::kInvalidIdError =
    StringPrintf(L"Required key '%ls' is missing or invalid.",
                 kIdKey).c_str();
const wchar_t* Extension::kInvalidNameError =
    StringPrintf(L"Required key '%ls' is missing or has invalid type.",
                 kNameKey).c_str();
const wchar_t* Extension::kInvalidDescriptionError =
    StringPrintf(L"Invalid type for '%ls' key.",
                 kDescriptionKey).c_str();
const wchar_t* Extension::kInvalidContentScriptsListError =
    StringPrintf(L"Invalid type for '%ls' key.",
                 kContentScriptsKey).c_str();
const wchar_t* Extension::kInvalidContentScriptError =
    StringPrintf(L"Invalid type for %ls at index ",
                 kContentScriptsKey).c_str();

bool Extension::InitFromValue(const DictionaryValue& source,
                              std::wstring* error) {
  // Check format version.
  int format_version = 0;
  if (!source.GetInteger(kFormatVersionKey, &format_version) ||
      format_version != kExpectedFormatVersion) {
    *error = kInvalidFormatVersionError;
    return false;
  }

  // Initialize id.
  if (!source.GetString(kIdKey, &id_)) {
    *error = kInvalidIdError;
    return false;
  }

  // Initialize name.
  if (!source.GetString(kNameKey, &name_)) {
    *error = kInvalidNameError;
    return false;
  }

  // Initialize description (optional).
  Value* value = NULL;
  if (source.Get(kDescriptionKey, &value)) {
    if (!value->GetAsString(&description_)) {
      *error = kInvalidDescriptionError;
      return false;
    }
  }

  // Initialize content scripts (optional).
  if (source.Get(kContentScriptsKey, &value)) {
    ListValue* list_value = NULL;
    if (value->GetType() != Value::TYPE_LIST) {
      *error = kInvalidContentScriptsListError;
      return false;
    } else {
      list_value = static_cast<ListValue*>(value);
    }

    for (size_t i = 0; i < list_value->GetSize(); ++i) {
      std::wstring content_script;
      if (!list_value->Get(i, &value) || !value->GetAsString(&content_script)) {
        *error = kInvalidContentScriptError;
        *error += IntToWString(i);
        return false;
      }

      content_scripts_.push_back(content_script);
    }
  }

  return true;
}

void Extension::CopyToValue(DictionaryValue* destination) {
  // Set format version
  destination->SetInteger(kFormatVersionKey,
                          kExpectedFormatVersion);

  // Copy id.
  destination->SetString(kIdKey, id_);

  // Copy name.
  destination->SetString(kNameKey, name_);

  // Copy description (optional).
  if (description_.size() > 0)
    destination->SetString(kDescriptionKey, description_);

  // Copy content scripts (optional).
  if (content_scripts_.size() > 0) {
    ListValue* list_value = new ListValue();
    destination->Set(kContentScriptsKey, list_value);

    for (size_t i = 0; i < content_scripts_.size(); ++i) {
      list_value->Set(i, Value::CreateStringValue(content_scripts_[i]));
    }
  }
}
<commit_msg>Fixed a bogus initialization of string constants.  The stack allocated string from StringPrintf gets destroyed right away, and c_str is just a pointer to its internal buffer, so the error constant was bogus memory.  This showed up in the purify tests.<commit_after>// Copyright (c) 2006-2008 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 "chrome/browser/extensions/extension.h"

#include "base/logging.h"
#include "base/string_util.h"

const FilePath::CharType* Extension::kManifestFilename =
    FILE_PATH_LITERAL("manifest");

const wchar_t* Extension::kFormatVersionKey = L"format_version";
const wchar_t* Extension::kIdKey = L"id";
const wchar_t* Extension::kNameKey = L"name";
const wchar_t* Extension::kDescriptionKey = L"description";
const wchar_t* Extension::kContentScriptsKey = L"content_scripts";

const wchar_t* Extension::kInvalidManifestError =
    L"Manifest is missing or invalid.";
const wchar_t* Extension::kInvalidFormatVersionError =
    L"Required key 'format_version' is missing or invalid";
const wchar_t* Extension::kInvalidIdError =
    L"Required key 'id' is missing or invalid.";
const wchar_t* Extension::kInvalidNameError =
    L"Required key 'name' is missing or has invalid type.";
const wchar_t* Extension::kInvalidDescriptionError =
    L"Invalid type for 'description' key.";
const wchar_t* Extension::kInvalidContentScriptsListError =
    L"Invalid type for 'content_scripts' key.";
const wchar_t* Extension::kInvalidContentScriptError =
    L"Invalid type for content_scripts at index ";

bool Extension::InitFromValue(const DictionaryValue& source,
                              std::wstring* error) {
  // Check format version.
  int format_version = 0;
  if (!source.GetInteger(kFormatVersionKey, &format_version) ||
      format_version != kExpectedFormatVersion) {
    *error = kInvalidFormatVersionError;
    return false;
  }

  // Initialize id.
  if (!source.GetString(kIdKey, &id_)) {
    *error = kInvalidIdError;
    return false;
  }

  // Initialize name.
  if (!source.GetString(kNameKey, &name_)) {
    *error = kInvalidNameError;
    return false;
  }

  // Initialize description (optional).
  Value* value = NULL;
  if (source.Get(kDescriptionKey, &value)) {
    if (!value->GetAsString(&description_)) {
      *error = kInvalidDescriptionError;
      return false;
    }
  }

  // Initialize content scripts (optional).
  if (source.Get(kContentScriptsKey, &value)) {
    ListValue* list_value = NULL;
    if (value->GetType() != Value::TYPE_LIST) {
      *error = kInvalidContentScriptsListError;
      return false;
    } else {
      list_value = static_cast<ListValue*>(value);
    }

    for (size_t i = 0; i < list_value->GetSize(); ++i) {
      std::wstring content_script;
      if (!list_value->Get(i, &value) || !value->GetAsString(&content_script)) {
        *error = kInvalidContentScriptError;
        *error += IntToWString(i);
        return false;
      }

      content_scripts_.push_back(content_script);
    }
  }

  return true;
}

void Extension::CopyToValue(DictionaryValue* destination) {
  // Set format version
  destination->SetInteger(kFormatVersionKey,
                          kExpectedFormatVersion);

  // Copy id.
  destination->SetString(kIdKey, id_);

  // Copy name.
  destination->SetString(kNameKey, name_);

  // Copy description (optional).
  if (description_.size() > 0)
    destination->SetString(kDescriptionKey, description_);

  // Copy content scripts (optional).
  if (content_scripts_.size() > 0) {
    ListValue* list_value = new ListValue();
    destination->Set(kContentScriptsKey, list_value);

    for (size_t i = 0; i < content_scripts_.size(); ++i) {
      list_value->Set(i, Value::CreateStringValue(content_scripts_[i]));
    }
  }
}
<|endoftext|>


<commit_before>#include "FboQuickView.h"

#include <QScopedPointer>
#include <QQuickItem>

FboQuickView::FboQuickView( QOpenGLContext* context /*= 0*/ )
    : FboQuickWindow( context ), m_qmlComponent( 0 ), m_rootItem( 0 )
{
}

FboQuickView::~FboQuickView()
{
}

QQmlContext* FboQuickView::rootContext() const
{
    return m_qmlEngine.rootContext();
}

void FboQuickView::setSource( const QUrl& source )
{
    if( m_rootItem ) {
        delete m_rootItem;
        m_rootItem = 0;
    }

    if( m_qmlComponent ) {
        delete m_qmlComponent;
        m_qmlComponent = 0;
    }

    if( !source.isEmpty() ) {
        m_qmlComponent = new QQmlComponent( &m_qmlEngine, &m_qmlEngine );
        connect( m_qmlComponent, &QQmlComponent::statusChanged,
                 this, &FboQuickView::componentStatusChanged );
        m_qmlComponent->loadUrl( source );
    }
}

void FboQuickView::setQml( const QString& qml, const QUrl& qmlUrl )
{
    if( m_rootItem ) {
        delete m_rootItem;
        m_rootItem = 0;
    }

    if( m_qmlComponent ) {
        delete m_qmlComponent;
        m_qmlComponent = 0;
    }

    if( !qml.isEmpty() ) {
        m_qmlComponent = new QQmlComponent( &m_qmlEngine, &m_qmlEngine );
        connect( m_qmlComponent, &QQmlComponent::statusChanged,
                 this, &FboQuickView::componentStatusChanged );
        m_qmlComponent->setData( qml.toUtf8(), qmlUrl );
    }
}

void FboQuickView::componentStatusChanged( QQmlComponent::Status status )
{
    Q_ASSERT( !m_rootItem );

    Q_EMIT statusChanged( status );

    if( QQmlComponent::Ready != status )
        return;

    QScopedPointer<QObject> rootObject( m_qmlComponent->create() );
    m_rootItem = qobject_cast<QQuickItem*>( rootObject.data() );

    if( !m_rootItem )
        return;

    contentItem()->setFocus( true );
    rootObject.take()->setParent( contentItem() );
    m_rootItem->setParentItem( contentItem() );

    QResizeEvent event( size(), size() );
    resizeEvent( &event );
}

void FboQuickView::resizeEvent( QResizeEvent* event )
{
    FboQuickWindow::resizeEvent( event );

    if( m_rootItem )
        m_rootItem->setSize( QSizeF( width(), height() ) );
}

QList<QQmlError> FboQuickView::errors() const
{
    if( m_qmlComponent )
        return m_qmlComponent->errors();

    return QList<QQmlError>();
}

FboQuickView::Status FboQuickView::status() const
{
    if( !m_qmlComponent )
        return QQmlComponent::Null;

    return m_qmlComponent->status();
}
<commit_msg>FboQuickViw: make statusChanged signal little more useful<commit_after>#include "FboQuickView.h"

#include <QScopedPointer>
#include <QQuickItem>

FboQuickView::FboQuickView( QOpenGLContext* context /*= 0*/ )
    : FboQuickWindow( context ), m_qmlComponent( 0 ), m_rootItem( 0 )
{
}

FboQuickView::~FboQuickView()
{
}

QQmlContext* FboQuickView::rootContext() const
{
    return m_qmlEngine.rootContext();
}

void FboQuickView::setSource( const QUrl& source )
{
    if( m_rootItem ) {
        delete m_rootItem;
        m_rootItem = 0;
    }

    if( m_qmlComponent ) {
        delete m_qmlComponent;
        m_qmlComponent = 0;
    }

    if( !source.isEmpty() ) {
        m_qmlComponent = new QQmlComponent( &m_qmlEngine, &m_qmlEngine );
        connect( m_qmlComponent, &QQmlComponent::statusChanged,
                 this, &FboQuickView::componentStatusChanged );
        m_qmlComponent->loadUrl( source );
    }
}

void FboQuickView::setQml( const QString& qml, const QUrl& qmlUrl )
{
    if( m_rootItem ) {
        delete m_rootItem;
        m_rootItem = 0;
    }

    if( m_qmlComponent ) {
        delete m_qmlComponent;
        m_qmlComponent = 0;
    }

    if( !qml.isEmpty() ) {
        m_qmlComponent = new QQmlComponent( &m_qmlEngine, &m_qmlEngine );
        connect( m_qmlComponent, &QQmlComponent::statusChanged,
                 this, &FboQuickView::componentStatusChanged );
        m_qmlComponent->setData( qml.toUtf8(), qmlUrl );
    }
}

void FboQuickView::componentStatusChanged( QQmlComponent::Status status )
{
    Q_ASSERT( !m_rootItem );

    if( QQmlComponent::Ready != status ) {
        Q_EMIT statusChanged( status );
        return;
    }

    QScopedPointer<QObject> rootObject( m_qmlComponent->create() );
    m_rootItem = qobject_cast<QQuickItem*>( rootObject.data() );

    if( !m_rootItem ) {
        Q_EMIT statusChanged( QQmlComponent::Error );
        return;
    }

    contentItem()->setFocus( true );
    rootObject.take()->setParent( contentItem() );
    m_rootItem->setParentItem( contentItem() );

    QResizeEvent event( size(), size() );
    resizeEvent( &event );

    Q_EMIT statusChanged( QQmlComponent::Ready );
}

void FboQuickView::resizeEvent( QResizeEvent* event )
{
    FboQuickWindow::resizeEvent( event );

    if( m_rootItem )
        m_rootItem->setSize( QSizeF( width(), height() ) );
}

QList<QQmlError> FboQuickView::errors() const
{
    if( m_qmlComponent )
        return m_qmlComponent->errors();

    return QList<QQmlError>();
}

FboQuickView::Status FboQuickView::status() const
{
    if( !m_qmlComponent )
        return QQmlComponent::Null;

    return m_qmlComponent->status();
}
<|endoftext|>


<commit_before>#include "mbed.h"
#include "test_env.h"

#define SIZE (10)
#define ADDR (0x90)

#if defined(TARGET_KL25Z)
I2CSlave slave(PTE0, PTE1);
#elif defined(TARGET_LPC4088)
I2CSlave slave(p9, p10);
#elif defined(TARGET_SAMR21G18A)
I2CSlave slave(PA16, PA17);
#elif defined(TARGET_SAMD21J18A) || defined(TARGET_SAMD21G18A) || defined(TARGET_SAML21J18A)
I2CSlave slave(PA08, PA09);
#else
I2CSlave slave(p28, p27);
#endif

 int main() {
     char buf[SIZE];

     slave.address(ADDR);

     while (1) {
         int i = slave.receive();
         switch (i) {
             case I2CSlave::ReadAddressed:
                 slave.write(buf, SIZE);
				 for(int i = 0; i < SIZE; i++){
				}
                 break;
             case I2CSlave::WriteAddressed:
                 slave.read(buf, SIZE);
                 for(int i = 0; i < SIZE; i++){
					buf[i]++;
				}
                 break;
         }
     }
 }
<commit_msg>Added TARGET_FF_ARDUINO to i2c_slave test<commit_after>#include "mbed.h"
#include "test_env.h"

#define SIZE (10)
#define ADDR (0x90)

#if defined(TARGET_KL25Z)
I2CSlave slave(PTE0, PTE1);
#elif defined(TARGET_LPC4088)
I2CSlave slave(p9, p10);
#elif defined(TARGET_SAMR21G18A)
I2CSlave slave(PA16, PA17);
#elif defined(TARGET_SAMD21J18A) || defined(TARGET_SAMD21G18A) || defined(TARGET_SAML21J18A)
I2CSlave slave(PA08, PA09);
#elif defined(TARGET_FF_ARDUINO)
I2CSlave slave(I2C_SDA, I2C_SCL);
#else
I2CSlave slave(p28, p27);
#endif

 int main() {
     char buf[SIZE];

     slave.address(ADDR);

     while (1) {
         int i = slave.receive();
         switch (i) {
             case I2CSlave::ReadAddressed:
                 slave.write(buf, SIZE);
				 for(int i = 0; i < SIZE; i++){
				}
                 break;
             case I2CSlave::WriteAddressed:
                 slave.read(buf, SIZE);
                 for(int i = 0; i < SIZE; i++){
					buf[i]++;
				}
                 break;
         }
     }
 }
<|endoftext|>


<commit_before>// Copyright (c) 2009 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 "chrome/browser/gtk/bookmark_menu_controller_gtk.h"

#include <gtk/gtk.h>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/gfx/gtk_util.h"
#include "base/string_util.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/gtk/bookmark_context_menu.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/gtk/gtk_dnd_util.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/menu_gtk.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/common/gtk_util.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "webkit/glue/window_open_disposition.h"

namespace {

void SetImageMenuItem(GtkWidget* menu_item, const SkBitmap& bitmap) {
  GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap);
  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
                                gtk_image_new_from_pixbuf(pixbuf));
  g_object_unref(pixbuf);
}

const BookmarkNode* GetNodeFromMenuItem(GtkWidget* menu_item) {
  return static_cast<const BookmarkNode*>(
      g_object_get_data(G_OBJECT(menu_item), "bookmark-node"));
}

const BookmarkNode* GetParentNodeFromEmptyMenuItem(GtkWidget* menu_item) {
  return static_cast<const BookmarkNode*>(
      g_object_get_data(G_OBJECT(menu_item), "parent-node"));
}

void* AsVoid(const BookmarkNode* node) {
  return const_cast<BookmarkNode*>(node);
}

}  // namespace

BookmarkMenuController::BookmarkMenuController(Browser* browser,
                                               Profile* profile,
                                               PageNavigator* navigator,
                                               GtkWindow* window,
                                               const BookmarkNode* node,
                                               int start_child_index,
                                               bool show_other_folder)
    : browser_(browser),
      profile_(profile),
      page_navigator_(navigator),
      parent_window_(window),
      node_(node),
      ignore_button_release_(false),
      triggering_widget_(NULL) {
  menu_.Own(gtk_menu_new());
  BuildMenu(node, start_child_index, menu_.get());
  g_signal_connect(menu_.get(), "hide",
                   G_CALLBACK(OnMenuHidden), this);
  gtk_widget_show_all(menu_.get());
}

BookmarkMenuController::~BookmarkMenuController() {
  profile_->GetBookmarkModel()->RemoveObserver(this);
  menu_.Destroy();
}

void BookmarkMenuController::Popup(GtkWidget* widget, gint button_type,
                                   guint32 timestamp) {
  profile_->GetBookmarkModel()->AddObserver(this);

  triggering_widget_ = widget;
  gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget),
                                    GTK_STATE_ACTIVE);
  gtk_menu_popup(GTK_MENU(menu_.get()), NULL, NULL,
                 &MenuGtk::MenuPositionFunc,
                 widget, button_type, timestamp);
}

void BookmarkMenuController::BookmarkModelChanged() {
  gtk_menu_popdown(GTK_MENU(menu_.get()));
}

void BookmarkMenuController::BookmarkNodeFavIconLoaded(
    BookmarkModel* model, const BookmarkNode* node) {
  std::map<const BookmarkNode*, GtkWidget*>::iterator it =
      node_to_menu_widget_map_.find(node);
  if (it != node_to_menu_widget_map_.end())
    SetImageMenuItem(it->second, model->GetFavIcon(node));
}

void BookmarkMenuController::NavigateToMenuItem(
    GtkWidget* menu_item,
    WindowOpenDisposition disposition) {
  const BookmarkNode* node = GetNodeFromMenuItem(menu_item);
  DCHECK(node);
  DCHECK(page_navigator_);
  page_navigator_->OpenURL(
      node->GetURL(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
}

void BookmarkMenuController::BuildMenu(const BookmarkNode* parent,
                                       int start_child_index,
                                       GtkWidget* menu) {
  DCHECK(!parent->GetChildCount() ||
         start_child_index < parent->GetChildCount());
  for (int i = start_child_index; i < parent->GetChildCount(); ++i) {
    const BookmarkNode* node = parent->GetChild(i);

    GtkWidget* menu_item = gtk_image_menu_item_new_with_label(
        WideToUTF8(node->GetTitle()).c_str());
    g_object_set_data(G_OBJECT(menu_item), "bookmark-node", AsVoid(node));
    g_signal_connect(G_OBJECT(menu_item), "button-press-event",
                     G_CALLBACK(OnButtonPressed), this);

    if (node->is_url()) {
      SkBitmap icon = profile_->GetBookmarkModel()->GetFavIcon(node);
      if (icon.width() == 0) {
        icon = *ResourceBundle::GetSharedInstance().
            GetBitmapNamed(IDR_DEFAULT_FAVICON);
      }
      SetImageMenuItem(menu_item, icon);
      g_signal_connect(G_OBJECT(menu_item), "activate",
                       G_CALLBACK(OnMenuItemActivated), this);
      g_signal_connect(G_OBJECT(menu_item), "button-release-event",
                       G_CALLBACK(OnButtonReleased), this);
    } else if (node->is_folder()) {
      SkBitmap* folder_icon = ResourceBundle::GetSharedInstance().
          GetBitmapNamed(IDR_BOOKMARK_BAR_FOLDER);
      SetImageMenuItem(menu_item, *folder_icon);

      GtkWidget* submenu = gtk_menu_new();
      BuildMenu(node, 0, submenu);
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
    } else {
      NOTREACHED();
    }

    gtk_drag_source_set(menu_item, GDK_BUTTON1_MASK,
                        NULL, 0, GDK_ACTION_MOVE);
    GtkDndUtil::SetSourceTargetListFromCodeMask(
        menu_item, GtkDndUtil::CHROME_BOOKMARK_ITEM);
    g_signal_connect(G_OBJECT(menu_item), "drag-begin",
                     G_CALLBACK(&OnMenuItemDragBegin), this);
    g_signal_connect(G_OBJECT(menu_item), "drag-end",
                     G_CALLBACK(&OnMenuItemDragEnd), this);
    g_signal_connect(G_OBJECT(menu_item), "drag-data-get",
                     G_CALLBACK(&OnMenuItemDragGet), this);

    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
    node_to_menu_widget_map_[node] = menu_item;
  }

  if (parent->GetChildCount() == 0) {
    GtkWidget* empty_menu = gtk_menu_item_new_with_label(
        l10n_util::GetStringUTF8(IDS_MENU_EMPTY_SUBMENU).c_str());
    gtk_widget_set_sensitive(empty_menu, FALSE);
    // We connect to the menu rather than the item because the item is
    // insensitive and doesn't listen for button presses.
    g_signal_connect(G_OBJECT(menu), "button-press-event",
                     G_CALLBACK(OnButtonPressed), this);
    g_object_set_data(G_OBJECT(menu), "parent-node", AsVoid(parent));
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), empty_menu);
  }
}

// static
gboolean BookmarkMenuController::OnButtonPressed(
    GtkWidget* sender,
    GdkEventButton* event,
    BookmarkMenuController* controller) {
  controller->ignore_button_release_ = false;

  if (event->button == 3) {
    // Show the right click menu and stop processing this button event.
    const BookmarkNode* node = GetNodeFromMenuItem(sender);
    const BookmarkNode* parent = node ? node->GetParent() :
        GetParentNodeFromEmptyMenuItem(sender);
    std::vector<const BookmarkNode*> nodes;
    if (node)
      nodes.push_back(node);
    controller->context_menu_.reset(
        new BookmarkContextMenu(
            sender, controller->profile_, controller->browser_,
            controller->page_navigator_, parent, nodes,
            BookmarkContextMenu::BOOKMARK_BAR));
    controller->context_menu_->PopupAsContext(event->time);
    return TRUE;
  }

  return FALSE;
}

// static
gboolean BookmarkMenuController::OnButtonReleased(
    GtkWidget* sender,
    GdkEventButton* event,
    BookmarkMenuController* controller) {
  if (controller->ignore_button_release_) {
    // Don't handle this message; it was a drag.
    controller->ignore_button_release_ = false;
    return FALSE;
  }

  // Releasing either button 1 or 2 should trigger the bookmark menu.
  if (event->button == 1 || event->button == 2) {
    WindowOpenDisposition disposition =
        event_utils::DispositionFromEventFlags(event->state);
    controller->NavigateToMenuItem(sender, disposition);

    // We need to manually dismiss the popup menu because we're overriding
    // button-release-event.
    gtk_menu_popdown(GTK_MENU(controller->menu_.get()));
    return TRUE;
  }

  return FALSE;
}

// static
void BookmarkMenuController::OnMenuHidden(GtkWidget* menu,
    BookmarkMenuController* controller) {
  if (controller->triggering_widget_) {
    gtk_chrome_button_unset_paint_state(
        GTK_CHROME_BUTTON(controller->triggering_widget_));
  }
}

// static
void BookmarkMenuController::OnMenuItemActivated(
    GtkMenuItem* menu_item, BookmarkMenuController* controller) {
  controller->NavigateToMenuItem(GTK_WIDGET(menu_item), CURRENT_TAB);
}

// static
void BookmarkMenuController::OnMenuItemDragBegin(
    GtkWidget* menu_item,
    GdkDragContext* drag_context,
    BookmarkMenuController* controller) {
  // The parent menu item might be removed during the drag. Ref it so |button|
  // won't get destroyed.
  g_object_ref(menu_item->parent);

  // Signal to any future OnButtonReleased calls that we're dragging instead of
  // pressing.
  controller->ignore_button_release_ = true;

  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(menu_item);
  GtkWidget* window = bookmark_utils::GetDragRepresentation(
      node, controller->model_,
      GtkThemeProvider::GetFrom(controller->profile_));
  gint x, y;
  gtk_widget_get_pointer(menu_item, &x, &y);
  gtk_drag_set_icon_widget(drag_context, window, x, y);

  // Hide our node.
  gtk_widget_hide(menu_item);
}

// static
void BookmarkMenuController::OnMenuItemDragEnd(
    GtkWidget* menu_item,
    GdkDragContext* drag_context,
    BookmarkMenuController* controller) {
  gtk_widget_show(menu_item);
  g_object_unref(menu_item->parent);
}

// static
void BookmarkMenuController::OnMenuItemDragGet(
    GtkWidget* widget, GdkDragContext* context,
    GtkSelectionData* selection_data,
    guint target_type, guint time,
    BookmarkMenuController* controller) {
  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(widget);
  bookmark_utils::WriteBookmarkToSelection(node, selection_data, target_type,
                                           controller->profile_);
}
<commit_msg>Fix some issues with bookmark bar folder menu.<commit_after>// Copyright (c) 2009 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 "chrome/browser/gtk/bookmark_menu_controller_gtk.h"

#include <gtk/gtk.h>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/gfx/gtk_util.h"
#include "base/string_util.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/gtk/bookmark_context_menu.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/gtk/gtk_dnd_util.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/menu_gtk.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/common/gtk_util.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "webkit/glue/window_open_disposition.h"

namespace {

void SetImageMenuItem(GtkWidget* menu_item, const SkBitmap& bitmap) {
  GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap);
  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
                                gtk_image_new_from_pixbuf(pixbuf));
  g_object_unref(pixbuf);
}

const BookmarkNode* GetNodeFromMenuItem(GtkWidget* menu_item) {
  return static_cast<const BookmarkNode*>(
      g_object_get_data(G_OBJECT(menu_item), "bookmark-node"));
}

const BookmarkNode* GetParentNodeFromEmptyMenu(GtkWidget* menu) {
  return static_cast<const BookmarkNode*>(
      g_object_get_data(G_OBJECT(menu), "parent-node"));
}

void* AsVoid(const BookmarkNode* node) {
  return const_cast<BookmarkNode*>(node);
}

}  // namespace

BookmarkMenuController::BookmarkMenuController(Browser* browser,
                                               Profile* profile,
                                               PageNavigator* navigator,
                                               GtkWindow* window,
                                               const BookmarkNode* node,
                                               int start_child_index,
                                               bool show_other_folder)
    : browser_(browser),
      profile_(profile),
      page_navigator_(navigator),
      parent_window_(window),
      node_(node),
      ignore_button_release_(false),
      triggering_widget_(NULL) {
  menu_.Own(gtk_menu_new());
  BuildMenu(node, start_child_index, menu_.get());
  g_signal_connect(menu_.get(), "hide",
                   G_CALLBACK(OnMenuHidden), this);
  gtk_widget_show_all(menu_.get());
}

BookmarkMenuController::~BookmarkMenuController() {
  profile_->GetBookmarkModel()->RemoveObserver(this);
  menu_.Destroy();
}

void BookmarkMenuController::Popup(GtkWidget* widget, gint button_type,
                                   guint32 timestamp) {
  profile_->GetBookmarkModel()->AddObserver(this);

  triggering_widget_ = widget;
  gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget),
                                    GTK_STATE_ACTIVE);
  gtk_menu_popup(GTK_MENU(menu_.get()), NULL, NULL,
                 &MenuGtk::MenuPositionFunc,
                 widget, button_type, timestamp);
}

void BookmarkMenuController::BookmarkModelChanged() {
  gtk_menu_popdown(GTK_MENU(menu_.get()));
}

void BookmarkMenuController::BookmarkNodeFavIconLoaded(
    BookmarkModel* model, const BookmarkNode* node) {
  std::map<const BookmarkNode*, GtkWidget*>::iterator it =
      node_to_menu_widget_map_.find(node);
  if (it != node_to_menu_widget_map_.end())
    SetImageMenuItem(it->second, model->GetFavIcon(node));
}

void BookmarkMenuController::NavigateToMenuItem(
    GtkWidget* menu_item,
    WindowOpenDisposition disposition) {
  const BookmarkNode* node = GetNodeFromMenuItem(menu_item);
  DCHECK(node);
  DCHECK(page_navigator_);
  page_navigator_->OpenURL(
      node->GetURL(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
}

void BookmarkMenuController::BuildMenu(const BookmarkNode* parent,
                                       int start_child_index,
                                       GtkWidget* menu) {
  DCHECK(!parent->GetChildCount() ||
         start_child_index < parent->GetChildCount());

  g_signal_connect(G_OBJECT(menu), "button-press-event",
                   G_CALLBACK(OnButtonPressed), this);

  for (int i = start_child_index; i < parent->GetChildCount(); ++i) {
    const BookmarkNode* node = parent->GetChild(i);

    GtkWidget* menu_item = gtk_image_menu_item_new_with_label(
        WideToUTF8(node->GetTitle()).c_str());
    g_object_set_data(G_OBJECT(menu_item), "bookmark-node", AsVoid(node));

    if (node->is_url()) {
      SkBitmap icon = profile_->GetBookmarkModel()->GetFavIcon(node);
      if (icon.width() == 0) {
        icon = *ResourceBundle::GetSharedInstance().
            GetBitmapNamed(IDR_DEFAULT_FAVICON);
      }
      SetImageMenuItem(menu_item, icon);
      g_signal_connect(G_OBJECT(menu_item), "activate",
                       G_CALLBACK(OnMenuItemActivated), this);
      g_signal_connect(G_OBJECT(menu_item), "button-release-event",
                       G_CALLBACK(OnButtonReleased), this);
    } else if (node->is_folder()) {
      SkBitmap* folder_icon = ResourceBundle::GetSharedInstance().
          GetBitmapNamed(IDR_BOOKMARK_BAR_FOLDER);
      SetImageMenuItem(menu_item, *folder_icon);

      GtkWidget* submenu = gtk_menu_new();
      BuildMenu(node, 0, submenu);
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
    } else {
      NOTREACHED();
    }

    gtk_drag_source_set(menu_item, GDK_BUTTON1_MASK,
                        NULL, 0, GDK_ACTION_MOVE);
    GtkDndUtil::SetSourceTargetListFromCodeMask(
        menu_item, GtkDndUtil::CHROME_BOOKMARK_ITEM);
    g_signal_connect(G_OBJECT(menu_item), "drag-begin",
                     G_CALLBACK(&OnMenuItemDragBegin), this);
    g_signal_connect(G_OBJECT(menu_item), "drag-end",
                     G_CALLBACK(&OnMenuItemDragEnd), this);
    g_signal_connect(G_OBJECT(menu_item), "drag-data-get",
                     G_CALLBACK(&OnMenuItemDragGet), this);

    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
    node_to_menu_widget_map_[node] = menu_item;
  }

  if (parent->GetChildCount() == 0) {
    GtkWidget* empty_menu = gtk_menu_item_new_with_label(
        l10n_util::GetStringUTF8(IDS_MENU_EMPTY_SUBMENU).c_str());
    gtk_widget_set_sensitive(empty_menu, FALSE);
    g_object_set_data(G_OBJECT(menu), "parent-node", AsVoid(parent));
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), empty_menu);
  }
}

// static
gboolean BookmarkMenuController::OnButtonPressed(
    GtkWidget* sender,
    GdkEventButton* event,
    BookmarkMenuController* controller) {
  controller->ignore_button_release_ = false;
  GtkMenuShell* menu_shell = GTK_MENU_SHELL(sender);

  if (event->button == 3) {
    // If the cursor is outside our bounds, pass this event up to the parent.
    if (!gtk_util::WidgetContainsCursor(sender)) {
      if (menu_shell->parent_menu_shell) {
        return OnButtonPressed(menu_shell->parent_menu_shell, event, controller);
      } else {
        // We are the top level menu; we can propagate no further.
        return FALSE;
      }
    }

    // This will return NULL if we are not an empty menu.
    const BookmarkNode* parent = GetParentNodeFromEmptyMenu(sender);
    bool is_empty_menu = !!parent;
    // If there is no active menu item and we are not an empty menu, then do
    // nothing.
    GtkWidget* menu_item = menu_shell->active_menu_item;
    if (!is_empty_menu && !menu_item)
      return FALSE;

    const BookmarkNode* node =
        menu_item ? GetNodeFromMenuItem(menu_item) : NULL;
    DCHECK_NE(is_empty_menu, !!node);
    if (!is_empty_menu)
      parent = node->GetParent();

    // Show the right click menu and stop processing this button event.
    std::vector<const BookmarkNode*> nodes;
    if (node)
      nodes.push_back(node);
    controller->context_menu_.reset(
        new BookmarkContextMenu(
            sender, controller->profile_, controller->browser_,
            controller->page_navigator_, parent, nodes,
            BookmarkContextMenu::BOOKMARK_BAR));
    controller->context_menu_->PopupAsContext(event->time);
    return TRUE;
  }

  return FALSE;
}

// static
gboolean BookmarkMenuController::OnButtonReleased(
    GtkWidget* sender,
    GdkEventButton* event,
    BookmarkMenuController* controller) {
  if (controller->ignore_button_release_) {
    // Don't handle this message; it was a drag.
    controller->ignore_button_release_ = false;
    return FALSE;
  }

  // Releasing either button 1 or 2 should trigger the bookmark menu.
  if (event->button == 1 || event->button == 2) {
    WindowOpenDisposition disposition =
        event_utils::DispositionFromEventFlags(event->state);
    controller->NavigateToMenuItem(sender, disposition);

    // We need to manually dismiss the popup menu because we're overriding
    // button-release-event.
    gtk_menu_popdown(GTK_MENU(controller->menu_.get()));
    return TRUE;
  }

  return FALSE;
}

// static
void BookmarkMenuController::OnMenuHidden(GtkWidget* menu,
    BookmarkMenuController* controller) {
  if (controller->triggering_widget_) {
    gtk_chrome_button_unset_paint_state(
        GTK_CHROME_BUTTON(controller->triggering_widget_));
  }
}

// static
void BookmarkMenuController::OnMenuItemActivated(
    GtkMenuItem* menu_item, BookmarkMenuController* controller) {
  controller->NavigateToMenuItem(GTK_WIDGET(menu_item), CURRENT_TAB);
}

// static
void BookmarkMenuController::OnMenuItemDragBegin(
    GtkWidget* menu_item,
    GdkDragContext* drag_context,
    BookmarkMenuController* controller) {
  // The parent menu item might be removed during the drag. Ref it so |button|
  // won't get destroyed.
  g_object_ref(menu_item->parent);

  // Signal to any future OnButtonReleased calls that we're dragging instead of
  // pressing.
  controller->ignore_button_release_ = true;

  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(menu_item);
  GtkWidget* window = bookmark_utils::GetDragRepresentation(
      node, controller->model_,
      GtkThemeProvider::GetFrom(controller->profile_));
  gint x, y;
  gtk_widget_get_pointer(menu_item, &x, &y);
  gtk_drag_set_icon_widget(drag_context, window, x, y);

  // Hide our node.
  gtk_widget_hide(menu_item);
}

// static
void BookmarkMenuController::OnMenuItemDragEnd(
    GtkWidget* menu_item,
    GdkDragContext* drag_context,
    BookmarkMenuController* controller) {
  gtk_widget_show(menu_item);
  g_object_unref(menu_item->parent);
}

// static
void BookmarkMenuController::OnMenuItemDragGet(
    GtkWidget* widget, GdkDragContext* context,
    GtkSelectionData* selection_data,
    guint target_type, guint time,
    BookmarkMenuController* controller) {
  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(widget);
  bookmark_utils::WriteBookmarkToSelection(node, selection_data, target_type,
                                           controller->profile_);
}
<|endoftext|>


<commit_before>// 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 "chrome/browser/gtk/bookmark_menu_controller_gtk.h"

#include <gtk/gtk.h>

#include "app/gtk_dnd_util.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/string_util.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/menu_gtk.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "gfx/gtk_util.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "webkit/glue/window_open_disposition.h"

namespace {

// TODO(estade): It might be a good idea to vary this by locale.
const int kMaxChars = 50;

void SetImageMenuItem(GtkWidget* menu_item,
                      const BookmarkNode* node,
                      BookmarkModel* model) {
  GdkPixbuf* pixbuf = bookmark_utils::GetPixbufForNode(node, model, true);
  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
                                gtk_image_new_from_pixbuf(pixbuf));
  g_object_unref(pixbuf);
}

const BookmarkNode* GetNodeFromMenuItem(GtkWidget* menu_item) {
  return static_cast<const BookmarkNode*>(
      g_object_get_data(G_OBJECT(menu_item), "bookmark-node"));
}

const BookmarkNode* GetParentNodeFromEmptyMenu(GtkWidget* menu) {
  return static_cast<const BookmarkNode*>(
      g_object_get_data(G_OBJECT(menu), "parent-node"));
}

void* AsVoid(const BookmarkNode* node) {
  return const_cast<BookmarkNode*>(node);
}

// The context menu has been dismissed, restore the X and application grabs
// to whichever menu last had them. (Assuming that menu is still showing.)
void OnContextMenuHide(GtkWidget* context_menu, GtkWidget* grab_menu) {
  gtk_util::GrabAllInput(grab_menu);

  // Match the ref we took when connecting this signal.
  g_object_unref(grab_menu);
}

}  // namespace

BookmarkMenuController::BookmarkMenuController(Browser* browser,
                                               Profile* profile,
                                               PageNavigator* navigator,
                                               GtkWindow* window,
                                               const BookmarkNode* node,
                                               int start_child_index)
    : browser_(browser),
      profile_(profile),
      page_navigator_(navigator),
      parent_window_(window),
      model_(profile->GetBookmarkModel()),
      node_(node),
      drag_icon_(NULL),
      ignore_button_release_(false),
      triggering_widget_(NULL) {
  menu_ = gtk_menu_new();
  BuildMenu(node, start_child_index, menu_);
  g_signal_connect(menu_, "hide",
                   G_CALLBACK(OnMenuHiddenThunk), this);
  gtk_widget_show_all(menu_);
}

BookmarkMenuController::~BookmarkMenuController() {
  profile_->GetBookmarkModel()->RemoveObserver(this);
  gtk_menu_popdown(GTK_MENU(menu_));
}

void BookmarkMenuController::Popup(GtkWidget* widget, gint button_type,
                                   guint32 timestamp) {
  profile_->GetBookmarkModel()->AddObserver(this);

  triggering_widget_ = widget;
  gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget),
                                    GTK_STATE_ACTIVE);
  gtk_menu_popup(GTK_MENU(menu_), NULL, NULL,
                 &MenuGtk::WidgetMenuPositionFunc,
                 widget, button_type, timestamp);
}

void BookmarkMenuController::BookmarkModelChanged() {
  gtk_menu_popdown(GTK_MENU(menu_));
}

void BookmarkMenuController::BookmarkNodeFavIconLoaded(
    BookmarkModel* model, const BookmarkNode* node) {
  std::map<const BookmarkNode*, GtkWidget*>::iterator it =
      node_to_menu_widget_map_.find(node);
  if (it != node_to_menu_widget_map_.end())
    SetImageMenuItem(it->second, node, model);
}

void BookmarkMenuController::WillExecuteCommand() {
  gtk_menu_popdown(GTK_MENU(menu_));
}

void BookmarkMenuController::CloseMenu() {
  context_menu_->Cancel();
}

void BookmarkMenuController::NavigateToMenuItem(
    GtkWidget* menu_item,
    WindowOpenDisposition disposition) {
  const BookmarkNode* node = GetNodeFromMenuItem(menu_item);
  DCHECK(node);
  DCHECK(page_navigator_);
  page_navigator_->OpenURL(
      node->GetURL(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
}

void BookmarkMenuController::BuildMenu(const BookmarkNode* parent,
                                       int start_child_index,
                                       GtkWidget* menu) {
  DCHECK(!parent->GetChildCount() ||
         start_child_index < parent->GetChildCount());

  g_signal_connect(menu, "button-press-event",
                   G_CALLBACK(OnButtonPressedThunk), this);

  for (int i = start_child_index; i < parent->GetChildCount(); ++i) {
    const BookmarkNode* node = parent->GetChild(i);

    // This breaks on word boundaries. Ideally we would break on character
    // boundaries.
    std::wstring elided_name =
        l10n_util::TruncateString(node->GetTitle(), kMaxChars);
    GtkWidget* menu_item =
        gtk_image_menu_item_new_with_label(WideToUTF8(elided_name).c_str());
    g_object_set_data(G_OBJECT(menu_item), "bookmark-node", AsVoid(node));
    SetImageMenuItem(menu_item, node, profile_->GetBookmarkModel());
    gtk_util::SetAlwaysShowImage(menu_item);

    g_signal_connect(menu_item, "button-release-event",
                     G_CALLBACK(OnButtonReleasedThunk), this);
    if (node->is_url()) {
      g_signal_connect(menu_item, "activate",
                       G_CALLBACK(OnMenuItemActivatedThunk), this);
    } else if (node->is_folder()) {
      GtkWidget* submenu = gtk_menu_new();
      BuildMenu(node, 0, submenu);
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
    } else {
      NOTREACHED();
    }

    gtk_drag_source_set(menu_item, GDK_BUTTON1_MASK, NULL, 0,
        static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_LINK));
    int target_mask = gtk_dnd_util::CHROME_BOOKMARK_ITEM;
    if (node->is_url())
      target_mask |= gtk_dnd_util::TEXT_URI_LIST | gtk_dnd_util::NETSCAPE_URL;
    gtk_dnd_util::SetSourceTargetListFromCodeMask(menu_item, target_mask);
    g_signal_connect(menu_item, "drag-begin",
                     G_CALLBACK(OnMenuItemDragBeginThunk), this);
    g_signal_connect(menu_item, "drag-end",
                     G_CALLBACK(OnMenuItemDragEndThunk), this);
    g_signal_connect(menu_item, "drag-data-get",
                     G_CALLBACK(OnMenuItemDragGetThunk), this);

    // It is important to connect to this signal after setting up the drag
    // source because we only want to stifle the menu's default handler and
    // not the handler that the drag source uses.
    if (node->is_folder()) {
      g_signal_connect(menu_item, "button-press-event",
                       G_CALLBACK(OnFolderButtonPressedThunk), this);
    }

    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
    node_to_menu_widget_map_[node] = menu_item;
  }

  if (parent->GetChildCount() == 0) {
    GtkWidget* empty_menu = gtk_menu_item_new_with_label(
        l10n_util::GetStringUTF8(IDS_MENU_EMPTY_SUBMENU).c_str());
    gtk_widget_set_sensitive(empty_menu, FALSE);
    g_object_set_data(G_OBJECT(menu), "parent-node", AsVoid(parent));
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), empty_menu);
  }
}

gboolean BookmarkMenuController::OnButtonPressed(
    GtkWidget* sender,
    GdkEventButton* event) {
  if (event->button == 1) {
    return FALSE;

  ignore_button_release_ = false;
  GtkMenuShell* menu_shell = GTK_MENU_SHELL(sender);
  // If the cursor is outside our bounds, pass this event up to the parent.
  if (!gtk_util::WidgetContainsCursor(sender)) {
    if (menu_shell->parent_menu_shell) {
      return OnButtonPressed(menu_shell->parent_menu_shell, event);
    } else {
      // We are the top level menu; we can propagate no further.
      return FALSE;
    }
  }

  // This will return NULL if we are not an empty menu.
  const BookmarkNode* parent = GetParentNodeFromEmptyMenu(sender);
  bool is_empty_menu = !!parent;
  // If there is no active menu item and we are not an empty menu, then do
  // nothing. This can happen if the user has canceled a context menu while
  // the cursor is hovering over a bookmark menu. Doing nothing is not optimal
  // (the hovered item should be active), but it's a hopefully rare corner
  // case.
  GtkWidget* menu_item = menu_shell->active_menu_item;
  if (!is_empty_menu && !menu_item)
    return TRUE;
  const BookmarkNode* node =
      menu_item ? GetNodeFromMenuItem(menu_item) : NULL;

  if (event->button == 2 && node) {
    bookmark_utils::OpenAll(parent_window_,
                            profile_, page_navigator_,
                            node, NEW_BACKGROUND_TAB);
    gtk_menu_popdown(GTK_MENU(menu_));
    return TRUE;
  } else if (event->button == 3) {
    DCHECK_NE(is_empty_menu, !!node);
    if (!is_empty_menu)
      parent = node->GetParent();

    // Show the right click menu and stop processing this button event.
    std::vector<const BookmarkNode*> nodes;
    if (node)
      nodes.push_back(node);
    context_menu_controller_.reset(
        new BookmarkContextMenuController(
            parent_window_, this, profile_,
            page_navigator_, parent, nodes));
    context_menu_.reset(
        new MenuGtk(NULL, context_menu_controller_->menu_model()));

    // Our bookmark folder menu loses the grab to the context menu. When the
    // context menu is hidden, re-assert our grab.
    GtkWidget* grabbing_menu = gtk_grab_get_current();
    g_object_ref(grabbing_menu);
    g_signal_connect(context_menu_->widget(), "hide",
                     G_CALLBACK(OnContextMenuHide), grabbing_menu);

    context_menu_->PopupAsContext(event->time);
    return TRUE;
  }

  return FALSE;
}

gboolean BookmarkMenuController::OnButtonReleased(
    GtkWidget* sender,
    GdkEventButton* event) {
  if (ignore_button_release_) {
    // Don't handle this message; it was a drag.
    ignore_button_release_ = false;
    return FALSE;
  }

  // Releasing either button 1 or 2 should trigger the bookmark.
  if (!gtk_menu_item_get_submenu(GTK_MENU_ITEM(sender))) {
    // The menu item is a link node.
    if (event->button == 1 || event->button == 2) {
      WindowOpenDisposition disposition =
          event_utils::DispositionFromEventFlags(event->state);
      NavigateToMenuItem(sender, disposition);

      // We need to manually dismiss the popup menu because we're overriding
      // button-release-event.
      gtk_menu_popdown(GTK_MENU(menu_));
      return TRUE;
    }
  } else {
    // The menu item is a folder node.
    if (event->button == 1) {
      // Having overriden the normal handling, we need to manually activate
      // the item.
      gtk_menu_shell_select_item(GTK_MENU_SHELL(sender->parent), sender);
      g_signal_emit_by_name(sender->parent, "activate-current");
      return TRUE;
    }
  }

  return FALSE;
}

gboolean BookmarkMenuController::OnFolderButtonPressed(
    GtkWidget* sender, GdkEventButton* event) {
  // The button press may start a drag; don't let the default handler run.
  if (event->button == 1)
    return TRUE;
  return FALSE;
}

void BookmarkMenuController::OnMenuHidden(GtkWidget* menu) {
  if (triggering_widget_)
    gtk_chrome_button_unset_paint_state(GTK_CHROME_BUTTON(triggering_widget_));
}

void BookmarkMenuController::OnMenuItemActivated(GtkWidget* menu_item) {
  NavigateToMenuItem(menu_item, CURRENT_TAB);
}

void BookmarkMenuController::OnMenuItemDragBegin(GtkWidget* menu_item,
                                                 GdkDragContext* drag_context) {
  // The parent menu item might be removed during the drag. Ref it so |button|
  // won't get destroyed.
  g_object_ref(menu_item->parent);

  // Signal to any future OnButtonReleased calls that we're dragging instead of
  // pressing.
  ignore_button_release_ = true;

  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(menu_item);
  drag_icon_ = bookmark_utils::GetDragRepresentationForNode(
      node, model_, GtkThemeProvider::GetFrom(profile_));
  gint x, y;
  gtk_widget_get_pointer(menu_item, &x, &y);
  gtk_drag_set_icon_widget(drag_context, drag_icon_, x, y);

  // Hide our node.
  gtk_widget_hide(menu_item);
}

void BookmarkMenuController::OnMenuItemDragEnd(GtkWidget* menu_item,
                                               GdkDragContext* drag_context) {
  gtk_widget_show(menu_item);
  g_object_unref(menu_item->parent);

  gtk_widget_destroy(drag_icon_);
  drag_icon_ = NULL;
}

void BookmarkMenuController::OnMenuItemDragGet(
    GtkWidget* widget, GdkDragContext* context,
    GtkSelectionData* selection_data,
    guint target_type, guint time) {
  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(widget);
  bookmark_utils::WriteBookmarkToSelection(node, selection_data, target_type,
                                           profile_);
}
<commit_msg>Linux: remove mismatched brace<commit_after>// 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 "chrome/browser/gtk/bookmark_menu_controller_gtk.h"

#include <gtk/gtk.h>

#include "app/gtk_dnd_util.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/string_util.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/menu_gtk.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "gfx/gtk_util.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "webkit/glue/window_open_disposition.h"

namespace {

// TODO(estade): It might be a good idea to vary this by locale.
const int kMaxChars = 50;

void SetImageMenuItem(GtkWidget* menu_item,
                      const BookmarkNode* node,
                      BookmarkModel* model) {
  GdkPixbuf* pixbuf = bookmark_utils::GetPixbufForNode(node, model, true);
  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
                                gtk_image_new_from_pixbuf(pixbuf));
  g_object_unref(pixbuf);
}

const BookmarkNode* GetNodeFromMenuItem(GtkWidget* menu_item) {
  return static_cast<const BookmarkNode*>(
      g_object_get_data(G_OBJECT(menu_item), "bookmark-node"));
}

const BookmarkNode* GetParentNodeFromEmptyMenu(GtkWidget* menu) {
  return static_cast<const BookmarkNode*>(
      g_object_get_data(G_OBJECT(menu), "parent-node"));
}

void* AsVoid(const BookmarkNode* node) {
  return const_cast<BookmarkNode*>(node);
}

// The context menu has been dismissed, restore the X and application grabs
// to whichever menu last had them. (Assuming that menu is still showing.)
void OnContextMenuHide(GtkWidget* context_menu, GtkWidget* grab_menu) {
  gtk_util::GrabAllInput(grab_menu);

  // Match the ref we took when connecting this signal.
  g_object_unref(grab_menu);
}

}  // namespace

BookmarkMenuController::BookmarkMenuController(Browser* browser,
                                               Profile* profile,
                                               PageNavigator* navigator,
                                               GtkWindow* window,
                                               const BookmarkNode* node,
                                               int start_child_index)
    : browser_(browser),
      profile_(profile),
      page_navigator_(navigator),
      parent_window_(window),
      model_(profile->GetBookmarkModel()),
      node_(node),
      drag_icon_(NULL),
      ignore_button_release_(false),
      triggering_widget_(NULL) {
  menu_ = gtk_menu_new();
  BuildMenu(node, start_child_index, menu_);
  g_signal_connect(menu_, "hide",
                   G_CALLBACK(OnMenuHiddenThunk), this);
  gtk_widget_show_all(menu_);
}

BookmarkMenuController::~BookmarkMenuController() {
  profile_->GetBookmarkModel()->RemoveObserver(this);
  gtk_menu_popdown(GTK_MENU(menu_));
}

void BookmarkMenuController::Popup(GtkWidget* widget, gint button_type,
                                   guint32 timestamp) {
  profile_->GetBookmarkModel()->AddObserver(this);

  triggering_widget_ = widget;
  gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget),
                                    GTK_STATE_ACTIVE);
  gtk_menu_popup(GTK_MENU(menu_), NULL, NULL,
                 &MenuGtk::WidgetMenuPositionFunc,
                 widget, button_type, timestamp);
}

void BookmarkMenuController::BookmarkModelChanged() {
  gtk_menu_popdown(GTK_MENU(menu_));
}

void BookmarkMenuController::BookmarkNodeFavIconLoaded(
    BookmarkModel* model, const BookmarkNode* node) {
  std::map<const BookmarkNode*, GtkWidget*>::iterator it =
      node_to_menu_widget_map_.find(node);
  if (it != node_to_menu_widget_map_.end())
    SetImageMenuItem(it->second, node, model);
}

void BookmarkMenuController::WillExecuteCommand() {
  gtk_menu_popdown(GTK_MENU(menu_));
}

void BookmarkMenuController::CloseMenu() {
  context_menu_->Cancel();
}

void BookmarkMenuController::NavigateToMenuItem(
    GtkWidget* menu_item,
    WindowOpenDisposition disposition) {
  const BookmarkNode* node = GetNodeFromMenuItem(menu_item);
  DCHECK(node);
  DCHECK(page_navigator_);
  page_navigator_->OpenURL(
      node->GetURL(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
}

void BookmarkMenuController::BuildMenu(const BookmarkNode* parent,
                                       int start_child_index,
                                       GtkWidget* menu) {
  DCHECK(!parent->GetChildCount() ||
         start_child_index < parent->GetChildCount());

  g_signal_connect(menu, "button-press-event",
                   G_CALLBACK(OnButtonPressedThunk), this);

  for (int i = start_child_index; i < parent->GetChildCount(); ++i) {
    const BookmarkNode* node = parent->GetChild(i);

    // This breaks on word boundaries. Ideally we would break on character
    // boundaries.
    std::wstring elided_name =
        l10n_util::TruncateString(node->GetTitle(), kMaxChars);
    GtkWidget* menu_item =
        gtk_image_menu_item_new_with_label(WideToUTF8(elided_name).c_str());
    g_object_set_data(G_OBJECT(menu_item), "bookmark-node", AsVoid(node));
    SetImageMenuItem(menu_item, node, profile_->GetBookmarkModel());
    gtk_util::SetAlwaysShowImage(menu_item);

    g_signal_connect(menu_item, "button-release-event",
                     G_CALLBACK(OnButtonReleasedThunk), this);
    if (node->is_url()) {
      g_signal_connect(menu_item, "activate",
                       G_CALLBACK(OnMenuItemActivatedThunk), this);
    } else if (node->is_folder()) {
      GtkWidget* submenu = gtk_menu_new();
      BuildMenu(node, 0, submenu);
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
    } else {
      NOTREACHED();
    }

    gtk_drag_source_set(menu_item, GDK_BUTTON1_MASK, NULL, 0,
        static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_LINK));
    int target_mask = gtk_dnd_util::CHROME_BOOKMARK_ITEM;
    if (node->is_url())
      target_mask |= gtk_dnd_util::TEXT_URI_LIST | gtk_dnd_util::NETSCAPE_URL;
    gtk_dnd_util::SetSourceTargetListFromCodeMask(menu_item, target_mask);
    g_signal_connect(menu_item, "drag-begin",
                     G_CALLBACK(OnMenuItemDragBeginThunk), this);
    g_signal_connect(menu_item, "drag-end",
                     G_CALLBACK(OnMenuItemDragEndThunk), this);
    g_signal_connect(menu_item, "drag-data-get",
                     G_CALLBACK(OnMenuItemDragGetThunk), this);

    // It is important to connect to this signal after setting up the drag
    // source because we only want to stifle the menu's default handler and
    // not the handler that the drag source uses.
    if (node->is_folder()) {
      g_signal_connect(menu_item, "button-press-event",
                       G_CALLBACK(OnFolderButtonPressedThunk), this);
    }

    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
    node_to_menu_widget_map_[node] = menu_item;
  }

  if (parent->GetChildCount() == 0) {
    GtkWidget* empty_menu = gtk_menu_item_new_with_label(
        l10n_util::GetStringUTF8(IDS_MENU_EMPTY_SUBMENU).c_str());
    gtk_widget_set_sensitive(empty_menu, FALSE);
    g_object_set_data(G_OBJECT(menu), "parent-node", AsVoid(parent));
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), empty_menu);
  }
}

gboolean BookmarkMenuController::OnButtonPressed(
    GtkWidget* sender,
    GdkEventButton* event) {
  if (event->button == 1)
    return FALSE;

  ignore_button_release_ = false;
  GtkMenuShell* menu_shell = GTK_MENU_SHELL(sender);
  // If the cursor is outside our bounds, pass this event up to the parent.
  if (!gtk_util::WidgetContainsCursor(sender)) {
    if (menu_shell->parent_menu_shell) {
      return OnButtonPressed(menu_shell->parent_menu_shell, event);
    } else {
      // We are the top level menu; we can propagate no further.
      return FALSE;
    }
  }

  // This will return NULL if we are not an empty menu.
  const BookmarkNode* parent = GetParentNodeFromEmptyMenu(sender);
  bool is_empty_menu = !!parent;
  // If there is no active menu item and we are not an empty menu, then do
  // nothing. This can happen if the user has canceled a context menu while
  // the cursor is hovering over a bookmark menu. Doing nothing is not optimal
  // (the hovered item should be active), but it's a hopefully rare corner
  // case.
  GtkWidget* menu_item = menu_shell->active_menu_item;
  if (!is_empty_menu && !menu_item)
    return TRUE;
  const BookmarkNode* node =
      menu_item ? GetNodeFromMenuItem(menu_item) : NULL;

  if (event->button == 2 && node) {
    bookmark_utils::OpenAll(parent_window_,
                            profile_, page_navigator_,
                            node, NEW_BACKGROUND_TAB);
    gtk_menu_popdown(GTK_MENU(menu_));
    return TRUE;
  } else if (event->button == 3) {
    DCHECK_NE(is_empty_menu, !!node);
    if (!is_empty_menu)
      parent = node->GetParent();

    // Show the right click menu and stop processing this button event.
    std::vector<const BookmarkNode*> nodes;
    if (node)
      nodes.push_back(node);
    context_menu_controller_.reset(
        new BookmarkContextMenuController(
            parent_window_, this, profile_,
            page_navigator_, parent, nodes));
    context_menu_.reset(
        new MenuGtk(NULL, context_menu_controller_->menu_model()));

    // Our bookmark folder menu loses the grab to the context menu. When the
    // context menu is hidden, re-assert our grab.
    GtkWidget* grabbing_menu = gtk_grab_get_current();
    g_object_ref(grabbing_menu);
    g_signal_connect(context_menu_->widget(), "hide",
                     G_CALLBACK(OnContextMenuHide), grabbing_menu);

    context_menu_->PopupAsContext(event->time);
    return TRUE;
  }

  return FALSE;
}

gboolean BookmarkMenuController::OnButtonReleased(
    GtkWidget* sender,
    GdkEventButton* event) {
  if (ignore_button_release_) {
    // Don't handle this message; it was a drag.
    ignore_button_release_ = false;
    return FALSE;
  }

  // Releasing either button 1 or 2 should trigger the bookmark.
  if (!gtk_menu_item_get_submenu(GTK_MENU_ITEM(sender))) {
    // The menu item is a link node.
    if (event->button == 1 || event->button == 2) {
      WindowOpenDisposition disposition =
          event_utils::DispositionFromEventFlags(event->state);
      NavigateToMenuItem(sender, disposition);

      // We need to manually dismiss the popup menu because we're overriding
      // button-release-event.
      gtk_menu_popdown(GTK_MENU(menu_));
      return TRUE;
    }
  } else {
    // The menu item is a folder node.
    if (event->button == 1) {
      // Having overriden the normal handling, we need to manually activate
      // the item.
      gtk_menu_shell_select_item(GTK_MENU_SHELL(sender->parent), sender);
      g_signal_emit_by_name(sender->parent, "activate-current");
      return TRUE;
    }
  }

  return FALSE;
}

gboolean BookmarkMenuController::OnFolderButtonPressed(
    GtkWidget* sender, GdkEventButton* event) {
  // The button press may start a drag; don't let the default handler run.
  if (event->button == 1)
    return TRUE;
  return FALSE;
}

void BookmarkMenuController::OnMenuHidden(GtkWidget* menu) {
  if (triggering_widget_)
    gtk_chrome_button_unset_paint_state(GTK_CHROME_BUTTON(triggering_widget_));
}

void BookmarkMenuController::OnMenuItemActivated(GtkWidget* menu_item) {
  NavigateToMenuItem(menu_item, CURRENT_TAB);
}

void BookmarkMenuController::OnMenuItemDragBegin(GtkWidget* menu_item,
                                                 GdkDragContext* drag_context) {
  // The parent menu item might be removed during the drag. Ref it so |button|
  // won't get destroyed.
  g_object_ref(menu_item->parent);

  // Signal to any future OnButtonReleased calls that we're dragging instead of
  // pressing.
  ignore_button_release_ = true;

  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(menu_item);
  drag_icon_ = bookmark_utils::GetDragRepresentationForNode(
      node, model_, GtkThemeProvider::GetFrom(profile_));
  gint x, y;
  gtk_widget_get_pointer(menu_item, &x, &y);
  gtk_drag_set_icon_widget(drag_context, drag_icon_, x, y);

  // Hide our node.
  gtk_widget_hide(menu_item);
}

void BookmarkMenuController::OnMenuItemDragEnd(GtkWidget* menu_item,
                                               GdkDragContext* drag_context) {
  gtk_widget_show(menu_item);
  g_object_unref(menu_item->parent);

  gtk_widget_destroy(drag_icon_);
  drag_icon_ = NULL;
}

void BookmarkMenuController::OnMenuItemDragGet(
    GtkWidget* widget, GdkDragContext* context,
    GtkSelectionData* selection_data,
    guint target_type, guint time) {
  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(widget);
  bookmark_utils::WriteBookmarkToSelection(node, selection_data, target_type,
                                           profile_);
}
<|endoftext|>