<commit_before>// 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 "content/shell/browser/shell_browser_main.h"

#include <iostream>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/browser/browser_main_runner.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/webkit_test_controller.h"
#include "content/shell/common/shell_switches.h"
#include "content/shell/common/webkit_test_helpers.h"
#include "content/test/webkit_support.h"
#include "net/base/net_util.h"

#if defined(OS_ANDROID)
#include "base/run_loop.h"
#include "content/shell/browser/shell_layout_tests_android.h"
#endif

namespace {

GURL GetURLForLayoutTest(const std::string& test_name,
                         base::FilePath* current_working_directory,
                         bool* enable_pixel_dumping,
                         std::string* expected_pixel_hash) {
  // A test name is formated like file:///path/to/test'--pixel-test'pixelhash
  std::string path_or_url = test_name;
  std::string pixel_switch;
  std::string pixel_hash;
  std::string::size_type separator_position = path_or_url.find('\'');
  if (separator_position != std::string::npos) {
    pixel_switch = path_or_url.substr(separator_position + 1);
    path_or_url.erase(separator_position);
  }
  separator_position = pixel_switch.find('\'');
  if (separator_position != std::string::npos) {
    pixel_hash = pixel_switch.substr(separator_position + 1);
    pixel_switch.erase(separator_position);
  }
  if (enable_pixel_dumping) {
    *enable_pixel_dumping =
        (pixel_switch == "--pixel-test" || pixel_switch == "-p");
  }
  if (expected_pixel_hash)
    *expected_pixel_hash = pixel_hash;

  GURL test_url;
#if defined(OS_ANDROID)
  if (content::GetTestUrlForAndroid(path_or_url, &test_url))
    return test_url;
#endif

  test_url = GURL(path_or_url);
  if (!(test_url.is_valid() && test_url.has_scheme())) {
    // We're outside of the message loop here, and this is a test.
    base::ThreadRestrictions::ScopedAllowIO allow_io;
#if defined(OS_WIN)
    std::wstring wide_path_or_url =
        base::SysNativeMBToWide(path_or_url);
    base::FilePath local_file(wide_path_or_url);
#else
    base::FilePath local_file(path_or_url);
#endif
    if (!base::PathExists(local_file)) {
      local_file = content::GetWebKitRootDirFilePath()
          .Append(FILE_PATH_LITERAL("LayoutTests")).Append(local_file);
    }
    test_url = net::FilePathToFileURL(base::MakeAbsoluteFilePath(local_file));
  }
  base::FilePath local_path;
  if (current_working_directory) {
    // We're outside of the message loop here, and this is a test.
    base::ThreadRestrictions::ScopedAllowIO allow_io;
    if (net::FileURLToFilePath(test_url, &local_path))
      *current_working_directory = local_path.DirName();
    else
      file_util::GetCurrentDirectory(current_working_directory);
  }
  return test_url;
}

bool GetNextTest(const CommandLine::StringVector& args,
                 size_t* position,
                 std::string* test) {
  if (*position >= args.size())
    return false;
  if (args[*position] == FILE_PATH_LITERAL("-"))
    return !!std::getline(std::cin, *test, '\n');
#if defined(OS_WIN)
  *test = WideToUTF8(args[(*position)++]);
#else
  *test = args[(*position)++];
#endif
  return true;
}

}  // namespace

// Main routine for running as the Browser process.
int ShellBrowserMain(
    const content::MainFunctionParams& parameters,
    const scoped_ptr<content::BrowserMainRunner>& main_runner) {
  bool layout_test_mode =
      CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
  base::ScopedTempDir browser_context_path_for_layout_tests;

  if (layout_test_mode) {
    CHECK(browser_context_path_for_layout_tests.CreateUniqueTempDir());
    CHECK(!browser_context_path_for_layout_tests.path().MaybeAsASCII().empty());
    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
        switches::kContentShellDataPath,
        browser_context_path_for_layout_tests.path().MaybeAsASCII());

#if defined(OS_ANDROID)
    content::EnsureInitializeForAndroidLayoutTests();
#endif
  }

  int exit_code = main_runner->Initialize(parameters);
  DCHECK_LT(exit_code, 0)
      << "BrowserMainRunner::Initialize failed in ShellBrowserMain";

  if (exit_code >= 0)
    return exit_code;

  if (CommandLine::ForCurrentProcess()->HasSwitch(
        switches::kCheckLayoutTestSysDeps)) {
    base::MessageLoop::current()->PostTask(FROM_HERE,
                                           base::MessageLoop::QuitClosure());
    main_runner->Run();
    content::Shell::CloseAllWindows();
    main_runner->Shutdown();
    return 0;
  }

  if (layout_test_mode) {
    content::WebKitTestController test_controller;
    {
      // We're outside of the message loop here, and this is a test.
      base::ThreadRestrictions::ScopedAllowIO allow_io;
      base::FilePath temp_path;
      file_util::GetTempDir(&temp_path);
      test_controller.SetTempPath(temp_path);
    }
    std::string test_string;
    CommandLine::StringVector args =
        CommandLine::ForCurrentProcess()->GetArgs();
    size_t command_line_position = 0;
    bool ran_at_least_once = false;

#if defined(OS_ANDROID)
    std::cout << "#READY\n";
    std::cout.flush();
#endif

    while (GetNextTest(args, &command_line_position, &test_string)) {
      if (test_string.empty())
        continue;
      if (test_string == "QUIT")
        break;

      bool enable_pixel_dumps;
      std::string pixel_hash;
      base::FilePath cwd;
      GURL test_url = GetURLForLayoutTest(
          test_string, &cwd, &enable_pixel_dumps, &pixel_hash);
      if (!content::WebKitTestController::Get()->PrepareForLayoutTest(
              test_url, cwd, enable_pixel_dumps, pixel_hash)) {
        break;
      }

      ran_at_least_once = true;
#if defined(OS_ANDROID)
      // The message loop on Android is provided by the system, and does not
      // offer a blocking Run() method. For layout tests, use a nested loop
      // together with a base::RunLoop so it can block until a QuitClosure.
      base::RunLoop run_loop;
      run_loop.Run();
#else
      main_runner->Run();
#endif

      if (!content::WebKitTestController::Get()->ResetAfterLayoutTest())
        break;

#if defined(OS_ANDROID)
      // There will be left-over tasks in the queue for Android because the
      // main window is being destroyed. Run them before starting the next test.
      base::MessageLoop::current()->RunUntilIdle();
#endif
    }
    if (!ran_at_least_once) {
      base::MessageLoop::current()->PostTask(FROM_HERE,
                                             base::MessageLoop::QuitClosure());
      main_runner->Run();
    }

#if defined(OS_ANDROID)
    // Android should only execute Shutdown() here when running layout tests.
    main_runner->Shutdown();
#endif

    exit_code = 0;
  }

#if !defined(OS_ANDROID)
  if (!layout_test_mode)
    exit_code = main_runner->Run();

  main_runner->Shutdown();
#endif

  return exit_code;
}
<commit_msg>Print #READY from content_shell for non-Android platforms.<commit_after>// 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 "content/shell/browser/shell_browser_main.h"

#include <iostream>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/browser/browser_main_runner.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/webkit_test_controller.h"
#include "content/shell/common/shell_switches.h"
#include "content/shell/common/webkit_test_helpers.h"
#include "content/test/webkit_support.h"
#include "net/base/net_util.h"

#if defined(OS_ANDROID)
#include "base/run_loop.h"
#include "content/shell/browser/shell_layout_tests_android.h"
#endif

namespace {

GURL GetURLForLayoutTest(const std::string& test_name,
                         base::FilePath* current_working_directory,
                         bool* enable_pixel_dumping,
                         std::string* expected_pixel_hash) {
  // A test name is formated like file:///path/to/test'--pixel-test'pixelhash
  std::string path_or_url = test_name;
  std::string pixel_switch;
  std::string pixel_hash;
  std::string::size_type separator_position = path_or_url.find('\'');
  if (separator_position != std::string::npos) {
    pixel_switch = path_or_url.substr(separator_position + 1);
    path_or_url.erase(separator_position);
  }
  separator_position = pixel_switch.find('\'');
  if (separator_position != std::string::npos) {
    pixel_hash = pixel_switch.substr(separator_position + 1);
    pixel_switch.erase(separator_position);
  }
  if (enable_pixel_dumping) {
    *enable_pixel_dumping =
        (pixel_switch == "--pixel-test" || pixel_switch == "-p");
  }
  if (expected_pixel_hash)
    *expected_pixel_hash = pixel_hash;

  GURL test_url;
#if defined(OS_ANDROID)
  if (content::GetTestUrlForAndroid(path_or_url, &test_url))
    return test_url;
#endif

  test_url = GURL(path_or_url);
  if (!(test_url.is_valid() && test_url.has_scheme())) {
    // We're outside of the message loop here, and this is a test.
    base::ThreadRestrictions::ScopedAllowIO allow_io;
#if defined(OS_WIN)
    std::wstring wide_path_or_url =
        base::SysNativeMBToWide(path_or_url);
    base::FilePath local_file(wide_path_or_url);
#else
    base::FilePath local_file(path_or_url);
#endif
    if (!base::PathExists(local_file)) {
      local_file = content::GetWebKitRootDirFilePath()
          .Append(FILE_PATH_LITERAL("LayoutTests")).Append(local_file);
    }
    test_url = net::FilePathToFileURL(base::MakeAbsoluteFilePath(local_file));
  }
  base::FilePath local_path;
  if (current_working_directory) {
    // We're outside of the message loop here, and this is a test.
    base::ThreadRestrictions::ScopedAllowIO allow_io;
    if (net::FileURLToFilePath(test_url, &local_path))
      *current_working_directory = local_path.DirName();
    else
      file_util::GetCurrentDirectory(current_working_directory);
  }
  return test_url;
}

bool GetNextTest(const CommandLine::StringVector& args,
                 size_t* position,
                 std::string* test) {
  if (*position >= args.size())
    return false;
  if (args[*position] == FILE_PATH_LITERAL("-"))
    return !!std::getline(std::cin, *test, '\n');
#if defined(OS_WIN)
  *test = WideToUTF8(args[(*position)++]);
#else
  *test = args[(*position)++];
#endif
  return true;
}

}  // namespace

// Main routine for running as the Browser process.
int ShellBrowserMain(
    const content::MainFunctionParams& parameters,
    const scoped_ptr<content::BrowserMainRunner>& main_runner) {
  bool layout_test_mode =
      CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
  base::ScopedTempDir browser_context_path_for_layout_tests;

  if (layout_test_mode) {
    CHECK(browser_context_path_for_layout_tests.CreateUniqueTempDir());
    CHECK(!browser_context_path_for_layout_tests.path().MaybeAsASCII().empty());
    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
        switches::kContentShellDataPath,
        browser_context_path_for_layout_tests.path().MaybeAsASCII());

#if defined(OS_ANDROID)
    content::EnsureInitializeForAndroidLayoutTests();
#endif
  }

  int exit_code = main_runner->Initialize(parameters);
  DCHECK_LT(exit_code, 0)
      << "BrowserMainRunner::Initialize failed in ShellBrowserMain";

  if (exit_code >= 0)
    return exit_code;

  if (CommandLine::ForCurrentProcess()->HasSwitch(
        switches::kCheckLayoutTestSysDeps)) {
    base::MessageLoop::current()->PostTask(FROM_HERE,
                                           base::MessageLoop::QuitClosure());
    main_runner->Run();
    content::Shell::CloseAllWindows();
    main_runner->Shutdown();
    return 0;
  }

  if (layout_test_mode) {
    content::WebKitTestController test_controller;
    {
      // We're outside of the message loop here, and this is a test.
      base::ThreadRestrictions::ScopedAllowIO allow_io;
      base::FilePath temp_path;
      file_util::GetTempDir(&temp_path);
      test_controller.SetTempPath(temp_path);
    }
    std::string test_string;
    CommandLine::StringVector args =
        CommandLine::ForCurrentProcess()->GetArgs();
    size_t command_line_position = 0;
    bool ran_at_least_once = false;

    std::cout << "#READY\n";
    std::cout.flush();

    while (GetNextTest(args, &command_line_position, &test_string)) {
      if (test_string.empty())
        continue;
      if (test_string == "QUIT")
        break;

      bool enable_pixel_dumps;
      std::string pixel_hash;
      base::FilePath cwd;
      GURL test_url = GetURLForLayoutTest(
          test_string, &cwd, &enable_pixel_dumps, &pixel_hash);
      if (!content::WebKitTestController::Get()->PrepareForLayoutTest(
              test_url, cwd, enable_pixel_dumps, pixel_hash)) {
        break;
      }

      ran_at_least_once = true;
#if defined(OS_ANDROID)
      // The message loop on Android is provided by the system, and does not
      // offer a blocking Run() method. For layout tests, use a nested loop
      // together with a base::RunLoop so it can block until a QuitClosure.
      base::RunLoop run_loop;
      run_loop.Run();
#else
      main_runner->Run();
#endif

      if (!content::WebKitTestController::Get()->ResetAfterLayoutTest())
        break;

#if defined(OS_ANDROID)
      // There will be left-over tasks in the queue for Android because the
      // main window is being destroyed. Run them before starting the next test.
      base::MessageLoop::current()->RunUntilIdle();
#endif
    }
    if (!ran_at_least_once) {
      base::MessageLoop::current()->PostTask(FROM_HERE,
                                             base::MessageLoop::QuitClosure());
      main_runner->Run();
    }

#if defined(OS_ANDROID)
    // Android should only execute Shutdown() here when running layout tests.
    main_runner->Shutdown();
#endif

    exit_code = 0;
  }

#if !defined(OS_ANDROID)
  if (!layout_test_mode)
    exit_code = main_runner->Run();

  main_runner->Shutdown();
#endif

  return exit_code;
}
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Aaron Kennedy <aaron.kennedy@jollamobile.com>
**
** This file is part of lipstick.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QDBusConnection>
#include "lipstickcompositorwindow.h"
#include "lipstickcompositor.h"
#include "windowmodel.h"

WindowModel::WindowModel()
: m_complete(false)
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!c) {
        qWarning("WindowModel: Compositor must be created before WindowModel");
    } else {
        c->m_windowModels.append(this);
    }

    QDBusConnection dbus = QDBusConnection::sessionBus();
    dbus.registerObject("/WindowModel", this, QDBusConnection::ExportAllSlots);
    dbus.registerService("org.nemomobile.lipstick");
}

WindowModel::~WindowModel()
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (c) c->m_windowModels.removeAll(this);
}

int WindowModel::itemCount() const
{
    return m_items.count();
}

int WindowModel::windowId(int index) const
{
    if (index < 0 || index >= m_items.count())
        return 0;
    return m_items.at(index);
}

int WindowModel::rowCount(const QModelIndex &) const
{
    return m_items.count();
}

QVariant WindowModel::data(const QModelIndex &index, int role) const
{
    int idx = index.row();
    if (idx < 0 || idx >= m_items.count())
        return QVariant();

    LipstickCompositor *c = LipstickCompositor::instance();
    if (role == Qt::UserRole + 1) {
        return m_items.at(idx);
    } else if (role == Qt::UserRole + 2) {
        QWaylandSurface *s = c->surfaceForId(m_items.at(idx));
        return s?s->processId():0;
    } else if (role == Qt::UserRole + 3) {
        LipstickCompositorWindow *w = static_cast<LipstickCompositorWindow *>(c->windowForId(m_items.at(idx)));
        return w->title();
    } else {
        return QVariant();
    }
}

QHash<int, QByteArray> WindowModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[Qt::UserRole + 1] = "window";
    roles[Qt::UserRole + 2] = "processId";
    roles[Qt::UserRole + 3] = "title";
    return roles;
}

void WindowModel::classBegin()
{
}

void WindowModel::componentComplete()
{
    m_complete = true;
    refresh();
}

/*!
    Reimplement this method to provide custom filtering.
*/
bool WindowModel::approveWindow(LipstickCompositorWindow *window)
{
    return window->isInProcess() == false &&
        window->category() != QLatin1String("overlay");
}

void WindowModel::addItem(int id)
{
    if (!m_complete)
        return;

    LipstickCompositor *c = LipstickCompositor::instance();
    LipstickCompositorWindow *window = static_cast<LipstickCompositorWindow *>(c->windowForId(id));
    if (!approveWindow(window))
        return;

    beginInsertRows(QModelIndex(), m_items.count(), m_items.count());
    m_items.append(id);
    endInsertRows();
    emit itemAdded(m_items.count() - 1);
    emit itemCountChanged();
}

void WindowModel::remItem(int id)
{
    if (!m_complete)
        return;

    int idx = m_items.indexOf(id);
    if (idx == -1)
        return;

    beginRemoveRows(QModelIndex(), idx, idx);
    m_items.removeAt(idx);
    endRemoveRows();
    emit itemCountChanged();
}

void WindowModel::titleChanged(int id)
{
    if (!m_complete)
        return;

    int idx = m_items.indexOf(id);
    if (idx == -1)
        return;

    emit dataChanged(index(idx, 0), index(idx, 0));
}

void WindowModel::refresh()
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!m_complete || !c)
        return;

    beginResetModel();

    m_items.clear();

    for (QHash<int, LipstickCompositorWindow *>::ConstIterator iter = c->m_mappedSurfaces.begin();
         iter != c->m_mappedSurfaces.end(); ++iter) {

        if (approveWindow(iter.value()))
            m_items.append(iter.key());
    }

    endResetModel();
}

// used by mapplauncherd to bring a binary to the front
void WindowModel::launchProcess(const QString &binaryName)
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!m_complete || !c)
        return;

    for (QHash<int, LipstickCompositorWindow *>::ConstIterator iter = c->m_mappedSurfaces.begin();
        iter != c->m_mappedSurfaces.end(); ++iter) {

        LipstickCompositorWindow *win = iter.value();
        if (!approveWindow(win))
            continue;

        QString pidFile = QString::fromLatin1("/proc/%1/cmdline").arg(win->processId());
        QFile f(pidFile);
        if (!f.open(QIODevice::ReadOnly)) {
            qWarning() << Q_FUNC_INFO << "Cannot open cmdline for " << pidFile;
            continue;
        }

        // cmdline contains a \0, so we use constData to truncate that away
        QByteArray proc = QByteArray(f.readAll().constData());

        if (proc != binaryName)
            continue;

        win->surface()->raiseRequested();
        break;
    }
}

<commit_msg>[windowmodel] Add support for multi-arg binaryName in launchProcess<commit_after>/***************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Aaron Kennedy <aaron.kennedy@jollamobile.com>
**
** This file is part of lipstick.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QDBusConnection>
#include "lipstickcompositorwindow.h"
#include "lipstickcompositor.h"
#include "windowmodel.h"

WindowModel::WindowModel()
: m_complete(false)
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!c) {
        qWarning("WindowModel: Compositor must be created before WindowModel");
    } else {
        c->m_windowModels.append(this);
    }

    QDBusConnection dbus = QDBusConnection::sessionBus();
    dbus.registerObject("/WindowModel", this, QDBusConnection::ExportAllSlots);
    dbus.registerService("org.nemomobile.lipstick");
}

WindowModel::~WindowModel()
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (c) c->m_windowModels.removeAll(this);
}

int WindowModel::itemCount() const
{
    return m_items.count();
}

int WindowModel::windowId(int index) const
{
    if (index < 0 || index >= m_items.count())
        return 0;
    return m_items.at(index);
}

int WindowModel::rowCount(const QModelIndex &) const
{
    return m_items.count();
}

QVariant WindowModel::data(const QModelIndex &index, int role) const
{
    int idx = index.row();
    if (idx < 0 || idx >= m_items.count())
        return QVariant();

    LipstickCompositor *c = LipstickCompositor::instance();
    if (role == Qt::UserRole + 1) {
        return m_items.at(idx);
    } else if (role == Qt::UserRole + 2) {
        QWaylandSurface *s = c->surfaceForId(m_items.at(idx));
        return s?s->processId():0;
    } else if (role == Qt::UserRole + 3) {
        LipstickCompositorWindow *w = static_cast<LipstickCompositorWindow *>(c->windowForId(m_items.at(idx)));
        return w->title();
    } else {
        return QVariant();
    }
}

QHash<int, QByteArray> WindowModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[Qt::UserRole + 1] = "window";
    roles[Qt::UserRole + 2] = "processId";
    roles[Qt::UserRole + 3] = "title";
    return roles;
}

void WindowModel::classBegin()
{
}

void WindowModel::componentComplete()
{
    m_complete = true;
    refresh();
}

/*!
    Reimplement this method to provide custom filtering.
*/
bool WindowModel::approveWindow(LipstickCompositorWindow *window)
{
    return window->isInProcess() == false &&
        window->category() != QLatin1String("overlay");
}

void WindowModel::addItem(int id)
{
    if (!m_complete)
        return;

    LipstickCompositor *c = LipstickCompositor::instance();
    LipstickCompositorWindow *window = static_cast<LipstickCompositorWindow *>(c->windowForId(id));
    if (!approveWindow(window))
        return;

    beginInsertRows(QModelIndex(), m_items.count(), m_items.count());
    m_items.append(id);
    endInsertRows();
    emit itemAdded(m_items.count() - 1);
    emit itemCountChanged();
}

void WindowModel::remItem(int id)
{
    if (!m_complete)
        return;

    int idx = m_items.indexOf(id);
    if (idx == -1)
        return;

    beginRemoveRows(QModelIndex(), idx, idx);
    m_items.removeAt(idx);
    endRemoveRows();
    emit itemCountChanged();
}

void WindowModel::titleChanged(int id)
{
    if (!m_complete)
        return;

    int idx = m_items.indexOf(id);
    if (idx == -1)
        return;

    emit dataChanged(index(idx, 0), index(idx, 0));
}

void WindowModel::refresh()
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!m_complete || !c)
        return;

    beginResetModel();

    m_items.clear();

    for (QHash<int, LipstickCompositorWindow *>::ConstIterator iter = c->m_mappedSurfaces.begin();
         iter != c->m_mappedSurfaces.end(); ++iter) {

        if (approveWindow(iter.value()))
            m_items.append(iter.key());
    }

    endResetModel();
}

// used by mapplauncherd to bring a binary to the front
void WindowModel::launchProcess(const QString &binaryName)
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!m_complete || !c)
        return;

    QStringList binaryParts = binaryName.split(QRegExp(QRegExp("\\s+")));

    for (QHash<int, LipstickCompositorWindow *>::ConstIterator iter = c->m_mappedSurfaces.begin();
        iter != c->m_mappedSurfaces.end(); ++iter) {

        LipstickCompositorWindow *win = iter.value();
        if (!approveWindow(win))
            continue;

        QString pidFile = QString::fromLatin1("/proc/%1/cmdline").arg(win->processId());
        QFile f(pidFile);
        if (!f.open(QIODevice::ReadOnly)) {
            qWarning() << Q_FUNC_INFO << "Cannot open cmdline for " << pidFile;
            continue;
        }

        // Command line arguments are split by '\0' in /proc/*/cmdline
        QStringList proc;
        QByteArray data = f.readAll();
        Q_FOREACH (const QByteArray &array, data.split('\0')) {
            QString part = QString::fromUtf8(array);
            if (part.size() > 0) {
                proc << part;
            }
        }

        // Cannot match, as the cmdline has less arguments than then binary part
        if (binaryParts.size() > proc.size()) {
            continue;
        }

        bool match = true;

        // All parts of binaryName must be contained in this order in the
        // process command line to match the given process
        for (int i=0; i<binaryParts.count(); i++) {
            if (proc[i] != binaryParts[i]) {
                match = false;
                break;
            }
        }

        if (match) {
            win->surface()->raiseRequested();
            break;
        }
    }
}

<|endoftext|>


<commit_before>#include "MCAddress.h"

#include <libetpan/libetpan.h>
#include <string.h>

using namespace mailcore;

static Array * lep_address_list_from_lep_mailbox(struct mailimf_mailbox_list * mb_list, int encoded);
static Array * lep_address_list_from_lep_addr(struct mailimf_address_list * addr_list, int encoded);

Address::Address()
{
    init();
}

Address::Address(Address * other)
{
    init();
    setDisplayName(other->displayName());
    setMailbox(other->mailbox());
}

void Address::init()
{
    mDisplayName = NULL;
    mMailbox = NULL;
}

Address::~Address()
{
    MC_SAFE_RELEASE(mDisplayName);
    MC_SAFE_RELEASE(mMailbox);
}

Address * Address::addressWithDisplayName(String * displayName, String * mailbox)
{
    Address * result = new Address();
    result->setDisplayName(displayName);
    result->setMailbox(mailbox);
    return (Address *) result->autorelease();
}

Address * Address::addressWithMailbox(String * mailbox)
{
    return addressWithDisplayName(NULL, mailbox);
}

Address * Address::addressWithIMFMailbox(struct mailimf_mailbox * mailbox)
{
    Address * address;

    address = new Address();
	if (mailbox->mb_display_name != NULL) {
        address->setDisplayName(String::stringByDecodingMIMEHeaderValue(mailbox->mb_display_name));
	}
	if (mailbox->mb_addr_spec != NULL) {
		address->setMailbox(String::stringWithUTF8Characters(mailbox->mb_addr_spec));
	}
    if (address->mailbox() == NULL) {
        address->setMailbox(String::string());
    }

    return (Address *) address->autorelease();
}

Address * Address::addressWithIMAPAddress(struct mailimap_address * imap_addr)
{
    char * dsp_name;
    Address * address;
    String * mailbox;

    if (imap_addr->ad_personal_name == NULL)
        dsp_name = NULL;
    else {
        dsp_name = imap_addr->ad_personal_name;
    }

    if (imap_addr->ad_host_name == NULL) {
        const char * addr;

        if (imap_addr->ad_mailbox_name == NULL) {
            addr = "";
        }
        else {
            addr = imap_addr->ad_mailbox_name;
        }
        mailbox = String::stringWithUTF8Characters(addr);
        if (mailbox == NULL) {
            mailbox = MCSTR("");
        }
    }
    else if (imap_addr->ad_mailbox_name == NULL) {
        // fix by Gabor Cselle, (http://gaborcselle.com/), reported 8/16/2009
        mailbox = String::stringWithUTF8Format("@%s", imap_addr->ad_host_name);
    }
    else {
        mailbox = String::stringWithUTF8Format("%s@%s", imap_addr->ad_mailbox_name, imap_addr->ad_host_name);
    }

    address = new Address();
    if (dsp_name != NULL) {
        address->setDisplayName(String::stringByDecodingMIMEHeaderValue(dsp_name));
    }
    address->setMailbox(mailbox);

    return (Address *) address->autorelease();
}

Address * Address::addressWithRFC822String(String * RFC822String)
{
    const char * utf8String;
    size_t currentIndex;
    struct mailimf_mailbox * mb;
    int r;
    Address * result;

    utf8String = RFC822String->UTF8Characters();
    currentIndex = 0;
    r = mailimf_mailbox_parse(utf8String, strlen(utf8String), &currentIndex, &mb);
    if (r != MAILIMF_NO_ERROR)
        return NULL;

    result = addressWithIMFMailbox(mb);
    mailimf_mailbox_free(mb);

    return result;
}

Address * Address::addressWithNonEncodedIMFMailbox(struct mailimf_mailbox * mailbox)
{
    Address * address;

    address = new Address();
	if (mailbox->mb_display_name != NULL) {
        address->setDisplayName(String::stringWithUTF8Characters(mailbox->mb_display_name));
	}
	if (mailbox->mb_addr_spec != NULL) {
		address->setMailbox(String::stringWithUTF8Characters(mailbox->mb_addr_spec));
	}
    if (address->mailbox() == NULL) {
        address->setMailbox(String::string());
    }

    return (Address *) address->autorelease();
}

Address * Address::addressWithNonEncodedRFC822String(String * nonEncodedRFC822String)
{
    const char * utf8String;
    size_t currentIndex;
    struct mailimf_mailbox * mb;
    int r;
    Address * result;

    utf8String = nonEncodedRFC822String->UTF8Characters();
    currentIndex = 0;
    r = mailimf_mailbox_parse(utf8String, strlen(utf8String), &currentIndex, &mb);
    if (r != MAILIMF_NO_ERROR)
        return NULL;

    result = addressWithNonEncodedIMFMailbox(mb);
    mailimf_mailbox_free(mb);

    return result;
}

Array * Address::addressesWithRFC822String(String * string)
{
	const char * utf8String;
	size_t currentIndex;
	struct mailimf_address_list * addr_list;
	Array * result;
	int r;

    utf8String = string->UTF8Characters();
    currentIndex = 0;

	r = mailimf_address_list_parse(utf8String, strlen(utf8String), &currentIndex, &addr_list);
    if (r != MAILIMF_NO_ERROR)
        return NULL;

	result = lep_address_list_from_lep_addr(addr_list, 1);
	mailimf_address_list_free(addr_list);

	return result;
}

Array * Address::addressesWithNonEncodedRFC822String(String * string)
{
	const char * utf8String;
	size_t currentIndex;
	struct mailimf_address_list * addr_list;
	Array * result;
	int r;

    utf8String = string->UTF8Characters();
    currentIndex = 0;

	r = mailimf_address_list_parse(utf8String, strlen(utf8String), &currentIndex, &addr_list);
    if (r != MAILIMF_NO_ERROR)
        return NULL;

	result = lep_address_list_from_lep_addr(addr_list, 0);
	mailimf_address_list_free(addr_list);

	return result;
}

String * Address::RFC822StringForAddresses(Array * addresses)
{
    String * result = String::string();
    for(unsigned int i = 0 ; i < addresses->count() ; i ++) {
        Address * address = (Address *) addresses->objectAtIndex(i);
        if (i != 0) {
            result->appendString(MCSTR(", "));
        }
        result->appendString(address->RFC822String());
    }
    return result;
}

String * Address::nonEncodedRFC822StringForAddresses(Array * addresses)
{
    String * result = String::string();
    for(unsigned int i = 0 ; i < addresses->count() ; i ++) {
        Address * address = (Address *) addresses->objectAtIndex(i);
        if (i != 0) {
            result->appendString(MCSTR(", "));
        }
        result->appendString(address->nonEncodedRFC822String());
    }
    return result;
}

String * Address::description()
{
    String * result = String::string();
    result->appendString(className());
    result->appendUTF8Format(":%p ", this);
    if (mDisplayName != NULL) {
        result->appendString(mDisplayName);
    }
    result->appendUTF8Characters(" <");
    if (mMailbox != NULL) {
        result->appendString(mMailbox);
    }
    result->appendUTF8Characters(">");

    return result;
}

bool Address::isEqual(Object * otherObject)
{
    Address * otherAddress = (Address *) otherObject;

    if (mDisplayName == NULL) {
        if (otherAddress->displayName() != NULL) {
            return false;
        }
    }
    else if (mDisplayName != NULL) {
        if (otherAddress->displayName() == NULL) {
            return false;
        }
        else {
            if (!mDisplayName->isEqual(otherAddress->displayName()))
                return false;
        }
    }

    if (mMailbox == NULL) {
        if (otherAddress->mailbox() != NULL) {
            return false;
        }
    }
    else if (mMailbox != NULL) {
        if (otherAddress->mailbox() == NULL) {
            return false;
        }
        else {
            if (!mMailbox->isEqual(otherAddress->mailbox()))
                return false;
        }
    }

    return true;
}

unsigned int Address::hash()
{
    unsigned int value;

    value = 0;
    if (mDisplayName != NULL) {
        value += mDisplayName->hash();
    }
    if (mMailbox != NULL) {
        value += mMailbox->hash();
    }

    return value;
}

Object * Address::copy()
{
    return new Address(this);
}

void Address::setDisplayName(String * displayName)
{
    MC_SAFE_REPLACE_COPY(String, mDisplayName, displayName);
}

String * Address::displayName()
{
    return mDisplayName;
}

void Address::setMailbox(String * mailbox)
{
    MC_SAFE_REPLACE_COPY(String, mMailbox, mailbox);
}

String * Address::mailbox()
{
    return mMailbox;
}

struct mailimf_address * Address::createIMFAddress()
{
	struct mailimf_mailbox * mailbox;
	struct mailimf_address * result;

    mailbox = createIMFMailbox();
	result = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mailbox, NULL);

	return result;
}

struct mailimf_mailbox * Address::createIMFMailbox()
{
	struct mailimf_mailbox * result;
	char * display_name;
	char * addr_spec;

	display_name = NULL;
	if (displayName() != NULL) {
        if (displayName()->length() > 0) {
            Data * data;

            data = displayName()->encodedAddressDisplayNameValue();
            if (data->bytes() != NULL) {
                display_name = strdup(data->bytes());
            }
        }
    }
	addr_spec = strdup(mailbox()->UTF8Characters());
	result = mailimf_mailbox_new(display_name, addr_spec);

	return result;
}

String * Address::RFC822String()
{
    struct mailimf_mailbox * mb;
    MMAPString * str;
    int col;
    struct mailimf_mailbox_list * mb_list;
    clist * list;
    String * result;

    mb = createIMFMailbox();

    list = clist_new();
    clist_append(list, mb);
    mb_list = mailimf_mailbox_list_new(list);

    str = mmap_string_new("");
    col = 0;
    mailimf_mailbox_list_write_mem(str, &col, mb_list);

    result = String::stringWithUTF8Characters(str->str);

    mailimf_mailbox_list_free(mb_list);
    mmap_string_free(str);

    return result;
}

String * Address::nonEncodedRFC822String()
{
    struct mailimf_mailbox * mb;
    MMAPString * str;
    int col;
    struct mailimf_mailbox_list * mb_list;
    clist * list;
    String * result;
	char * display_name;
	char * addr_spec;

	display_name = NULL;
	if (displayName() != NULL) {
        if (displayName()->length() > 0) {
            display_name = strdup(displayName()->UTF8Characters());
        }
    }
    if ((mailbox() == NULL) || (mailbox()->length() == 0)) {
        addr_spec = strdup("invalid");
    }
    else {
        addr_spec = strdup(mailbox()->UTF8Characters());
    }
    mb = mailimf_mailbox_new(display_name, addr_spec);

    list = clist_new();
    clist_append(list, mb);
    mb_list = mailimf_mailbox_list_new(list);

    str = mmap_string_new("");
    col = 0;
    mailimf_mailbox_list_write_mem(str, &col, mb_list);

    result = String::stringWithUTF8Characters(str->str);

    mailimf_mailbox_list_free(mb_list);
    mmap_string_free(str);

    return result;
}

static Array * lep_address_list_from_lep_mailbox(struct mailimf_mailbox_list * mb_list, int encoded)
{
	Array * result;
	clistiter * cur;

	result = Array::array();
	for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ; cur = clist_next(cur)) {
		struct mailimf_mailbox * mb;
		Address * address;

		mb = (mailimf_mailbox *) clist_content(cur);
		if (encoded) {
			address = Address::addressWithIMFMailbox(mb);
		}
		else {
			address = Address::addressWithNonEncodedIMFMailbox(mb);
		}
		result->addObject(address);
	}

	return result;
}

static Array * lep_address_list_from_lep_addr(struct mailimf_address_list * addr_list, int encoded)
{
	Array * result;
	clistiter * cur;

	result = Array::array();

	for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ;
		cur = clist_next(cur)) {
		struct mailimf_address * addr;

		addr =  (mailimf_address *) clist_content(cur);
		switch (addr->ad_type) {
			case MAILIMF_ADDRESS_MAILBOX:
			{
				Address * address;

				if (encoded) {
					address = Address::addressWithIMFMailbox(addr->ad_data.ad_mailbox);
				}
				else {
					address = Address::addressWithNonEncodedIMFMailbox(addr->ad_data.ad_mailbox);
				}
				result->addObject(address);
				break;
			}

			case MAILIMF_ADDRESS_GROUP:
			{
				if (addr->ad_data.ad_group->grp_mb_list != NULL) {
					Array * subArray;

					subArray = lep_address_list_from_lep_mailbox(addr->ad_data.ad_group->grp_mb_list, encoded);
					result->addObjectsFromArray(subArray);
				}
				break;
			}
		}
	}

	return result;
}

static void * createObject()
{
    return new Address();
}

HashMap * Address::serializable()
{
    HashMap * result = Object::serializable();
    if (mailbox() != NULL) {
        result->setObjectForKey(MCSTR("mailbox"), mailbox());
    }
    if (displayName() != NULL) {
        result->setObjectForKey(MCSTR("displayName"), displayName());
    }
    return result;
}

void Address::importSerializable(HashMap * serializable)
{
    setMailbox((String *) serializable->objectForKey(MCSTR("mailbox")));
    setDisplayName((String *) serializable->objectForKey(MCSTR("mailbox")));
}

__attribute__((constructor))
static void initialize()
{
    Object::registerObjectConstructor("mailcore::Address", &createObject);
}

<commit_msg>use the correct key name when reading the Address displayName from a HashMap<commit_after>#include "MCAddress.h"

#include <libetpan/libetpan.h>
#include <string.h>

using namespace mailcore;

static Array * lep_address_list_from_lep_mailbox(struct mailimf_mailbox_list * mb_list, int encoded);
static Array * lep_address_list_from_lep_addr(struct mailimf_address_list * addr_list, int encoded);

Address::Address()
{
    init();
}

Address::Address(Address * other)
{
    init();
    setDisplayName(other->displayName());
    setMailbox(other->mailbox());
}

void Address::init()
{
    mDisplayName = NULL;
    mMailbox = NULL;
}

Address::~Address()
{
    MC_SAFE_RELEASE(mDisplayName);
    MC_SAFE_RELEASE(mMailbox);
}

Address * Address::addressWithDisplayName(String * displayName, String * mailbox)
{
    Address * result = new Address();
    result->setDisplayName(displayName);
    result->setMailbox(mailbox);
    return (Address *) result->autorelease();
}

Address * Address::addressWithMailbox(String * mailbox)
{
    return addressWithDisplayName(NULL, mailbox);
}

Address * Address::addressWithIMFMailbox(struct mailimf_mailbox * mailbox)
{
    Address * address;

    address = new Address();
	if (mailbox->mb_display_name != NULL) {
        address->setDisplayName(String::stringByDecodingMIMEHeaderValue(mailbox->mb_display_name));
	}
	if (mailbox->mb_addr_spec != NULL) {
		address->setMailbox(String::stringWithUTF8Characters(mailbox->mb_addr_spec));
	}
    if (address->mailbox() == NULL) {
        address->setMailbox(String::string());
    }

    return (Address *) address->autorelease();
}

Address * Address::addressWithIMAPAddress(struct mailimap_address * imap_addr)
{
    char * dsp_name;
    Address * address;
    String * mailbox;

    if (imap_addr->ad_personal_name == NULL)
        dsp_name = NULL;
    else {
        dsp_name = imap_addr->ad_personal_name;
    }

    if (imap_addr->ad_host_name == NULL) {
        const char * addr;

        if (imap_addr->ad_mailbox_name == NULL) {
            addr = "";
        }
        else {
            addr = imap_addr->ad_mailbox_name;
        }
        mailbox = String::stringWithUTF8Characters(addr);
        if (mailbox == NULL) {
            mailbox = MCSTR("");
        }
    }
    else if (imap_addr->ad_mailbox_name == NULL) {
        // fix by Gabor Cselle, (http://gaborcselle.com/), reported 8/16/2009
        mailbox = String::stringWithUTF8Format("@%s", imap_addr->ad_host_name);
    }
    else {
        mailbox = String::stringWithUTF8Format("%s@%s", imap_addr->ad_mailbox_name, imap_addr->ad_host_name);
    }

    address = new Address();
    if (dsp_name != NULL) {
        address->setDisplayName(String::stringByDecodingMIMEHeaderValue(dsp_name));
    }
    address->setMailbox(mailbox);

    return (Address *) address->autorelease();
}

Address * Address::addressWithRFC822String(String * RFC822String)
{
    const char * utf8String;
    size_t currentIndex;
    struct mailimf_mailbox * mb;
    int r;
    Address * result;

    utf8String = RFC822String->UTF8Characters();
    currentIndex = 0;
    r = mailimf_mailbox_parse(utf8String, strlen(utf8String), &currentIndex, &mb);
    if (r != MAILIMF_NO_ERROR)
        return NULL;

    result = addressWithIMFMailbox(mb);
    mailimf_mailbox_free(mb);

    return result;
}

Address * Address::addressWithNonEncodedIMFMailbox(struct mailimf_mailbox * mailbox)
{
    Address * address;

    address = new Address();
	if (mailbox->mb_display_name != NULL) {
        address->setDisplayName(String::stringWithUTF8Characters(mailbox->mb_display_name));
	}
	if (mailbox->mb_addr_spec != NULL) {
		address->setMailbox(String::stringWithUTF8Characters(mailbox->mb_addr_spec));
	}
    if (address->mailbox() == NULL) {
        address->setMailbox(String::string());
    }

    return (Address *) address->autorelease();
}

Address * Address::addressWithNonEncodedRFC822String(String * nonEncodedRFC822String)
{
    const char * utf8String;
    size_t currentIndex;
    struct mailimf_mailbox * mb;
    int r;
    Address * result;

    utf8String = nonEncodedRFC822String->UTF8Characters();
    currentIndex = 0;
    r = mailimf_mailbox_parse(utf8String, strlen(utf8String), &currentIndex, &mb);
    if (r != MAILIMF_NO_ERROR)
        return NULL;

    result = addressWithNonEncodedIMFMailbox(mb);
    mailimf_mailbox_free(mb);

    return result;
}

Array * Address::addressesWithRFC822String(String * string)
{
	const char * utf8String;
	size_t currentIndex;
	struct mailimf_address_list * addr_list;
	Array * result;
	int r;

    utf8String = string->UTF8Characters();
    currentIndex = 0;

	r = mailimf_address_list_parse(utf8String, strlen(utf8String), &currentIndex, &addr_list);
    if (r != MAILIMF_NO_ERROR)
        return NULL;

	result = lep_address_list_from_lep_addr(addr_list, 1);
	mailimf_address_list_free(addr_list);

	return result;
}

Array * Address::addressesWithNonEncodedRFC822String(String * string)
{
	const char * utf8String;
	size_t currentIndex;
	struct mailimf_address_list * addr_list;
	Array * result;
	int r;

    utf8String = string->UTF8Characters();
    currentIndex = 0;

	r = mailimf_address_list_parse(utf8String, strlen(utf8String), &currentIndex, &addr_list);
    if (r != MAILIMF_NO_ERROR)
        return NULL;

	result = lep_address_list_from_lep_addr(addr_list, 0);
	mailimf_address_list_free(addr_list);

	return result;
}

String * Address::RFC822StringForAddresses(Array * addresses)
{
    String * result = String::string();
    for(unsigned int i = 0 ; i < addresses->count() ; i ++) {
        Address * address = (Address *) addresses->objectAtIndex(i);
        if (i != 0) {
            result->appendString(MCSTR(", "));
        }
        result->appendString(address->RFC822String());
    }
    return result;
}

String * Address::nonEncodedRFC822StringForAddresses(Array * addresses)
{
    String * result = String::string();
    for(unsigned int i = 0 ; i < addresses->count() ; i ++) {
        Address * address = (Address *) addresses->objectAtIndex(i);
        if (i != 0) {
            result->appendString(MCSTR(", "));
        }
        result->appendString(address->nonEncodedRFC822String());
    }
    return result;
}

String * Address::description()
{
    String * result = String::string();
    result->appendString(className());
    result->appendUTF8Format(":%p ", this);
    if (mDisplayName != NULL) {
        result->appendString(mDisplayName);
    }
    result->appendUTF8Characters(" <");
    if (mMailbox != NULL) {
        result->appendString(mMailbox);
    }
    result->appendUTF8Characters(">");

    return result;
}

bool Address::isEqual(Object * otherObject)
{
    Address * otherAddress = (Address *) otherObject;

    if (mDisplayName == NULL) {
        if (otherAddress->displayName() != NULL) {
            return false;
        }
    }
    else if (mDisplayName != NULL) {
        if (otherAddress->displayName() == NULL) {
            return false;
        }
        else {
            if (!mDisplayName->isEqual(otherAddress->displayName()))
                return false;
        }
    }

    if (mMailbox == NULL) {
        if (otherAddress->mailbox() != NULL) {
            return false;
        }
    }
    else if (mMailbox != NULL) {
        if (otherAddress->mailbox() == NULL) {
            return false;
        }
        else {
            if (!mMailbox->isEqual(otherAddress->mailbox()))
                return false;
        }
    }

    return true;
}

unsigned int Address::hash()
{
    unsigned int value;

    value = 0;
    if (mDisplayName != NULL) {
        value += mDisplayName->hash();
    }
    if (mMailbox != NULL) {
        value += mMailbox->hash();
    }

    return value;
}

Object * Address::copy()
{
    return new Address(this);
}

void Address::setDisplayName(String * displayName)
{
    MC_SAFE_REPLACE_COPY(String, mDisplayName, displayName);
}

String * Address::displayName()
{
    return mDisplayName;
}

void Address::setMailbox(String * mailbox)
{
    MC_SAFE_REPLACE_COPY(String, mMailbox, mailbox);
}

String * Address::mailbox()
{
    return mMailbox;
}

struct mailimf_address * Address::createIMFAddress()
{
	struct mailimf_mailbox * mailbox;
	struct mailimf_address * result;

    mailbox = createIMFMailbox();
	result = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mailbox, NULL);

	return result;
}

struct mailimf_mailbox * Address::createIMFMailbox()
{
	struct mailimf_mailbox * result;
	char * display_name;
	char * addr_spec;

	display_name = NULL;
	if (displayName() != NULL) {
        if (displayName()->length() > 0) {
            Data * data;

            data = displayName()->encodedAddressDisplayNameValue();
            if (data->bytes() != NULL) {
                display_name = strdup(data->bytes());
            }
        }
    }
	addr_spec = strdup(mailbox()->UTF8Characters());
	result = mailimf_mailbox_new(display_name, addr_spec);

	return result;
}

String * Address::RFC822String()
{
    struct mailimf_mailbox * mb;
    MMAPString * str;
    int col;
    struct mailimf_mailbox_list * mb_list;
    clist * list;
    String * result;

    mb = createIMFMailbox();

    list = clist_new();
    clist_append(list, mb);
    mb_list = mailimf_mailbox_list_new(list);

    str = mmap_string_new("");
    col = 0;
    mailimf_mailbox_list_write_mem(str, &col, mb_list);

    result = String::stringWithUTF8Characters(str->str);

    mailimf_mailbox_list_free(mb_list);
    mmap_string_free(str);

    return result;
}

String * Address::nonEncodedRFC822String()
{
    struct mailimf_mailbox * mb;
    MMAPString * str;
    int col;
    struct mailimf_mailbox_list * mb_list;
    clist * list;
    String * result;
	char * display_name;
	char * addr_spec;

	display_name = NULL;
	if (displayName() != NULL) {
        if (displayName()->length() > 0) {
            display_name = strdup(displayName()->UTF8Characters());
        }
    }
    if ((mailbox() == NULL) || (mailbox()->length() == 0)) {
        addr_spec = strdup("invalid");
    }
    else {
        addr_spec = strdup(mailbox()->UTF8Characters());
    }
    mb = mailimf_mailbox_new(display_name, addr_spec);

    list = clist_new();
    clist_append(list, mb);
    mb_list = mailimf_mailbox_list_new(list);

    str = mmap_string_new("");
    col = 0;
    mailimf_mailbox_list_write_mem(str, &col, mb_list);

    result = String::stringWithUTF8Characters(str->str);

    mailimf_mailbox_list_free(mb_list);
    mmap_string_free(str);

    return result;
}

static Array * lep_address_list_from_lep_mailbox(struct mailimf_mailbox_list * mb_list, int encoded)
{
	Array * result;
	clistiter * cur;

	result = Array::array();
	for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ; cur = clist_next(cur)) {
		struct mailimf_mailbox * mb;
		Address * address;

		mb = (mailimf_mailbox *) clist_content(cur);
		if (encoded) {
			address = Address::addressWithIMFMailbox(mb);
		}
		else {
			address = Address::addressWithNonEncodedIMFMailbox(mb);
		}
		result->addObject(address);
	}

	return result;
}

static Array * lep_address_list_from_lep_addr(struct mailimf_address_list * addr_list, int encoded)
{
	Array * result;
	clistiter * cur;

	result = Array::array();

	for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ;
		cur = clist_next(cur)) {
		struct mailimf_address * addr;

		addr =  (mailimf_address *) clist_content(cur);
		switch (addr->ad_type) {
			case MAILIMF_ADDRESS_MAILBOX:
			{
				Address * address;

				if (encoded) {
					address = Address::addressWithIMFMailbox(addr->ad_data.ad_mailbox);
				}
				else {
					address = Address::addressWithNonEncodedIMFMailbox(addr->ad_data.ad_mailbox);
				}
				result->addObject(address);
				break;
			}

			case MAILIMF_ADDRESS_GROUP:
			{
				if (addr->ad_data.ad_group->grp_mb_list != NULL) {
					Array * subArray;

					subArray = lep_address_list_from_lep_mailbox(addr->ad_data.ad_group->grp_mb_list, encoded);
					result->addObjectsFromArray(subArray);
				}
				break;
			}
		}
	}

	return result;
}

static void * createObject()
{
    return new Address();
}

HashMap * Address::serializable()
{
    HashMap * result = Object::serializable();
    if (mailbox() != NULL) {
        result->setObjectForKey(MCSTR("mailbox"), mailbox());
    }
    if (displayName() != NULL) {
        result->setObjectForKey(MCSTR("displayName"), displayName());
    }
    return result;
}

void Address::importSerializable(HashMap * serializable)
{
    setMailbox((String *) serializable->objectForKey(MCSTR("mailbox")));
    setDisplayName((String *) serializable->objectForKey(MCSTR("displayName")));
}

__attribute__((constructor))
static void initialize()
{
    Object::registerObjectConstructor("mailcore::Address", &createObject);
}

<|endoftext|>


<commit_before>/*
 * Bullet OSG Framework.
 * The bullet environment module.
 *
 * Copyright (c) 2015 Jérémie Decock <jd.jdhp@gmail.com>
 *
 * www.jdhp.org
 */

#include "bullet_environment.h"

#include <iostream>

#include <Eigen/Dense>

#include <btBulletDynamicsCommon.h>

std::map<btDynamicsWorld *, botsim::BulletEnvironment *> botsim::BulletEnvironment::tickCallbackPointerMap;

/*
 * TODO
 * Well... it sucks; because of the way it has been designed in Bullet, this
 * callback *must* be a static function...
 * This is dirty and not convenient at all...
 */
void botsim::BulletEnvironment::tickCallback(btDynamicsWorld * world, btScalar time_step) {
    //std::cout << "The world just ticked by " << static_cast<float>(time_step) << " seconds" << std::endl;

    std::map<btDynamicsWorld *, BulletEnvironment *>::iterator it;
    it = botsim::BulletEnvironment::tickCallbackPointerMap.find(world);

    if(it != botsim::BulletEnvironment::tickCallbackPointerMap.end()) {
        // Element found;
        it->second->notifyTick();
    }
}

botsim::BulletEnvironment::BulletEnvironment(
        std::set<botsim::Object *> object_set,
        std::set<botsim::Part *> part_set,
        std::set<botsim::Controller *> controller_set,
        double bullet_time_step_duration_sec,
        double bullet_tick_duration_sec,
        int bullet_max_ticks_per_time_step,
        double simulation_duration_sec) :
            objectSet(object_set),
            partSet(part_set),
            controllerSet(controller_set),
            bulletTimeStepDurationSec(bullet_time_step_duration_sec),
            bulletTickDurationSec(bullet_tick_duration_sec),
            bulletMaxTicksPerTimeStep(bullet_max_ticks_per_time_step),
            simulationDurationSec(simulation_duration_sec) {

    // Set bullet constants
    this->gravity = -10.;

    // Setup bullet
    this->broadphase = new btDbvtBroadphase();

    this->collisionConfiguration = new btDefaultCollisionConfiguration();
    this->collisionDispatcher = new btCollisionDispatcher(this->collisionConfiguration);

    this->constraintSolver = new btSequentialImpulseConstraintSolver();

    this->dynamicsWorld = new btDiscreteDynamicsWorld(this->collisionDispatcher,
            this->broadphase,
            this->constraintSolver,
            this->collisionConfiguration);
    this->dynamicsWorld->setGravity(btVector3(0, 0, this->gravity));

    // This is a workaround for btDynamicsWorld::setInternalTickCallback().
    botsim::BulletEnvironment::tickCallbackPointerMap[this->dynamicsWorld] = this;

    // setInternalTickCallback() attachs a callback for internal ticks (substeps).
    // Only one callback can be attached (this is not an "observer pattern").
    // See: http://bulletphysics.org/mediawiki-1.5.8/index.php/Simulation_Tick_Callbacks
    this->dynamicsWorld->setInternalTickCallback(botsim::BulletEnvironment::tickCallback);

    // Add rigid bodies ///////////////

    // Objects
    std::set<botsim::Object *>::iterator object_it;
    std::set<botsim::Part *>::iterator part_it;
    std::set<botsim::Joint *>::iterator joint_it;
    std::set<botsim::Actuator *>::iterator actuator_it;

    for(object_it = this->objectSet.begin() ; object_it != this->objectSet.end() ; object_it++) {
        std::set<botsim::Part *> part_set = (*object_it)->getPartSet();

        /*
         * Directly adding object's parts to this->dynamicsWorld from here is
         * probably a bad idea:
         * - there are a risk to have the same part multiple times in
         *   this->ObjectSet and this->partSet;
         * - requires to update other modules like osgEnvironment (requires to
         *   add another loop to get objects parts to display for instance).
         * Instead, see the alternative method below.
         */
        //for(part_it = part_set.begin() ; part_it != part_set.end() ; part_it++) {
        //    this->dynamicsWorld->addRigidBody((*part_it)->getRigidBody());
        //}

        /*
         * Take each part of the object and add it to this->partSet.
         * This method has multiple advantages:
         * - no risk to have the same part multiple times in this->ObjectSet
         *   and this->partSet ; this->partSet is the only set of parts
         *   considered by bullet, open scene graph, ...
         * - no needs to update other modules like osgEnvironment (no need to
         *   add another loop to get objects parts to display for instance).
         */
        this->partSet.insert(part_set.begin(), part_set.end());

        /*
         * Add object's joints (i.e. Bullet's constraints).
         */
        std::set<botsim::Joint *> joint_set = (*object_it)->getJointSet();
        for(joint_it = joint_set.begin() ; joint_it != joint_set.end() ; joint_it++) {
            this->dynamicsWorld->addConstraint((*joint_it)->getBulletTypedConstraint());
        }

        /*
         * Add object's actuators (i.e. Bullet's constraints).
         */
        std::set<botsim::Actuator *> actuator_set = (*object_it)->getActuatorSet();
        for(actuator_it = actuator_set.begin() ; actuator_it != actuator_set.end() ; actuator_it++) {
            this->dynamicsWorld->addConstraint((*actuator_it)->getBulletTypedConstraint());
        }
    }

    // Parts
    for(part_it = this->partSet.begin() ; part_it != this->partSet.end() ; part_it++) {
        std::cout << "Add " << (*part_it)->getName() << std::endl;
        this->dynamicsWorld->addRigidBody((*part_it)->getRigidBody());
    }

    // Start the user clock
    this->userStartTime = std::chrono::system_clock::now();

    // Init the simulation clock
    this->elapsedSimulationTimeSec = 0.;
    this->elapsedSimulationTimeSecTickRes = 0.;
}

botsim::BulletEnvironment::~BulletEnvironment() {
    botsim::BulletEnvironment::tickCallbackPointerMap.erase(this->dynamicsWorld);

    delete this->dynamicsWorld;

    delete this->constraintSolver;
    delete this->collisionConfiguration;
    delete this->collisionDispatcher;
    delete this->broadphase;
}

btDiscreteDynamicsWorld * botsim::BulletEnvironment::getDynamicsWorld() const {
    return this->dynamicsWorld;
}

/**
 *
 */
void botsim::BulletEnvironment::run() {

    // Check some variables ///////////////////////////////

    // assert this->getBulletTimeStepDurationSec() > 0.
    if(this->getBulletTimeStepDurationSec() <= 0.) {
        throw std::invalid_argument("BulletEnvironment::bulletTimeStepDurationSec received a negative value. Within \"healless\" mode, this variable must receive a positive value.");
    }

    // assert this->getSimulationDurationSec() > 0.
    if(this->getSimulationDurationSec() <= 0.) {
        throw std::invalid_argument("BulletEnvironment::simulationDurationSec received a negative value. Within \"healless\" mode, this variable must receive a positive value.");
    }

    // Main loop (simulation loop) ////////////////////////

    while( this->getElapsedSimulationTimeSec() < this->getSimulationDurationSec() ) {
        // Update the physics
        this->stepSimulation(this->getBulletTimeStepDurationSec());
    }
}

/**
 *
 */
void botsim::BulletEnvironment::stepSimulation(const double time_step_duration_sec) {
    this->elapsedSimulationTimeSec += time_step_duration_sec;

    btScalar bullet_time_step_duration_sec = btScalar(time_step_duration_sec);
    btScalar bullet_tick_duration_sec = this->bulletTickDurationSec;
    int bullet_max_ticks_per_time_step = this->bulletMaxTicksPerTimeStep;

    // Warn the user if timeStepDuration > maxTicksPerTimeStep * tickDuration
    // cf. http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World
    if(bullet_time_step_duration_sec > (bullet_max_ticks_per_time_step * bullet_tick_duration_sec)) {
        std::cerr << "Warning: simulation time will be lost (timeStepDuration > maxTicksPerTimeStep * tickDuration)" << std::endl; // TODO: improve this message...
    }

    /*
     * getDynamicsWorld()->stepSimulation()
     * (cf. http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World)
     *
     * The first parameter is the easy one. It's simply the amount of time to
     * step the simulation by. Typically you're going to be passing it the time
     * since you last called it
     *
     * Bullet maintains an internal clock, in order to keep the actual length
     * of ticks constant. This is pivotally important for framerate
     * independence. The third parameter is the size of that internal step.
     *
     * The second parameter is the maximum number of steps that Bullet is
     * allowed to take each time you call it. If you pass a very large timeStep
     * as the first parameter [say, five times the size of the fixed internal
     * time step], then you must increase the number of maxTicksPerTimeStep to
     * compensate for this, otherwise your simulation is "losing" time.
     */
    this->getDynamicsWorld()->stepSimulation(bullet_time_step_duration_sec, bullet_max_ticks_per_time_step, bullet_tick_duration_sec);

    this->notifyTimeStep();
}

/**
 * Realtime case.
 */
void botsim::BulletEnvironment::stepSimulation() {
    // Define the static variable previous_user_time: the previous actual user time (i.e. outside the simulation).
    static std::chrono::time_point<std::chrono::system_clock> previous_user_time = std::chrono::system_clock::now();

    // Get the elapsed user time (in seconds) since the previous time step.
    std::chrono::time_point<std::chrono::system_clock> current_user_time = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds_since_previous_step = current_user_time - previous_user_time;
    double time_step_duration_sec = elapsed_seconds_since_previous_step.count();

    // Update previous_user_time
    previous_user_time = std::chrono::system_clock::now();

    // Step simulation
    this->stepSimulation(time_step_duration_sec);
}

void botsim::BulletEnvironment::resetSimulation() {
    std::cout << "Reset simulation" << std::endl;

    // TODO

    //this->constraintSolver->reset();
    //this->dynamicsWorld->clearForces();
    //this->broadphase->resetPool(this->collisionDispatcher);
    ////m_clock.reset();

    //btOverlappingPairCache* pair_cache = this->dynamicsWorld->getBroadphase()->getOverlappingPairCache();
    //btBroadphasePairArray& pair_array = pair_cache->getOverlappingPairArray();
    //for(int i = 0; i < pair_array.size(); i++) {
    //    pair_cache->cleanOverlappingPair(pair_array[i], this->dynamicsWorld->getDispatcher());
    //}
    // TODO: reset the initial position, angle, velocity, mass, ... of each parts.
}

void botsim::BulletEnvironment::attachTickObserver(botsim::BulletTickObserver * p_observer) {
    this->tickObserverSet.insert(p_observer);
}

void botsim::BulletEnvironment::detachTickObserver(botsim::BulletTickObserver * p_observer) {
    this->tickObserverSet.erase(p_observer);
}

void botsim::BulletEnvironment::attachTimeStepObserver(botsim::TimeStepObserver * p_observer) {
    this->timeStepObserverSet.insert(p_observer);
}

void botsim::BulletEnvironment::detachTimeStepObserver(botsim::TimeStepObserver * p_observer) {
    this->timeStepObserverSet.erase(p_observer);
}

void botsim::BulletEnvironment::notifyTick() {

    // Udate elapsedSimulationTimeSecTickRes
    this->elapsedSimulationTimeSecTickRes += this->bulletTickDurationSec;

    // Update all observers
    std::set<botsim::BulletTickObserver *>::iterator it;
    for(it = this->tickObserverSet.begin() ; it != this->tickObserverSet.end() ; it++) {
        (*it)->update(this);
    }

    // Update each controller
    std::set<botsim::Controller *>::iterator controller_it;
    for(controller_it = this->controllerSet.begin() ; controller_it != this->controllerSet.end() ; controller_it++) {
        (*controller_it)->updateActuators();
    }
}

void botsim::BulletEnvironment::notifyTimeStep() {
    std::set<botsim::TimeStepObserver *>::iterator it;
    for(it = this->timeStepObserverSet.begin() ; it != this->timeStepObserverSet.end() ; it++) {
        (*it)->update(this);
    }
}

/**
 * return the simulation time (i.e. the time within the simulation) elapsed
 * since the beginning of the simulation.
 */
double botsim::BulletEnvironment::getElapsedSimulationTimeSec() const {
    return this->elapsedSimulationTimeSec;
}

/**
 * return the simulation time (i.e. the time within the simulation) elapsed
 * since the beginning of the simulation.
 */
double botsim::BulletEnvironment::getElapsedSimulationTimeSecTickRes() const {
    return this->elapsedSimulationTimeSecTickRes;
}

/**
 * return the actual time (i.e. the time outside the simulation) elapsed since
 * the beginning of the simulation.
 */
double botsim::BulletEnvironment::getElapsedUserTimeSec() const {
    std::chrono::time_point<std::chrono::system_clock> current_user_time = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = current_user_time - this->userStartTime;
    return elapsed_seconds.count();
}

/**
 *
 */
double botsim::BulletEnvironment::getBulletTimeStepDurationSec() const {
    return this->bulletTimeStepDurationSec;
}

/**
 *
 */
double botsim::BulletEnvironment::getBulletTickDurationSec() const {
    return this->bulletTickDurationSec;
}

/**
 *
 */
double botsim::BulletEnvironment::getBulletMaxTicksPerTimeStep() const {
    return this->bulletMaxTicksPerTimeStep;
}

/**
 *
 */
double botsim::BulletEnvironment::getSimulationDurationSec() const {
    return this->simulationDurationSec;
}
<commit_msg>Let 'BulletEnvironment' be quiet.<commit_after>/*
 * Bullet OSG Framework.
 * The bullet environment module.
 *
 * Copyright (c) 2015 Jérémie Decock <jd.jdhp@gmail.com>
 *
 * www.jdhp.org
 */

#include "bullet_environment.h"

#include <iostream>

#include <Eigen/Dense>

#include <btBulletDynamicsCommon.h>

std::map<btDynamicsWorld *, botsim::BulletEnvironment *> botsim::BulletEnvironment::tickCallbackPointerMap;

/*
 * TODO
 * Well... it sucks; because of the way it has been designed in Bullet, this
 * callback *must* be a static function...
 * This is dirty and not convenient at all...
 */
void botsim::BulletEnvironment::tickCallback(btDynamicsWorld * world, btScalar time_step) {
    //std::cout << "The world just ticked by " << static_cast<float>(time_step) << " seconds" << std::endl;

    std::map<btDynamicsWorld *, BulletEnvironment *>::iterator it;
    it = botsim::BulletEnvironment::tickCallbackPointerMap.find(world);

    if(it != botsim::BulletEnvironment::tickCallbackPointerMap.end()) {
        // Element found;
        it->second->notifyTick();
    }
}

botsim::BulletEnvironment::BulletEnvironment(
        std::set<botsim::Object *> object_set,
        std::set<botsim::Part *> part_set,
        std::set<botsim::Controller *> controller_set,
        double bullet_time_step_duration_sec,
        double bullet_tick_duration_sec,
        int bullet_max_ticks_per_time_step,
        double simulation_duration_sec) :
            objectSet(object_set),
            partSet(part_set),
            controllerSet(controller_set),
            bulletTimeStepDurationSec(bullet_time_step_duration_sec),
            bulletTickDurationSec(bullet_tick_duration_sec),
            bulletMaxTicksPerTimeStep(bullet_max_ticks_per_time_step),
            simulationDurationSec(simulation_duration_sec) {

    // Set bullet constants
    this->gravity = -10.;

    // Setup bullet
    this->broadphase = new btDbvtBroadphase();

    this->collisionConfiguration = new btDefaultCollisionConfiguration();
    this->collisionDispatcher = new btCollisionDispatcher(this->collisionConfiguration);

    this->constraintSolver = new btSequentialImpulseConstraintSolver();

    this->dynamicsWorld = new btDiscreteDynamicsWorld(this->collisionDispatcher,
            this->broadphase,
            this->constraintSolver,
            this->collisionConfiguration);
    this->dynamicsWorld->setGravity(btVector3(0, 0, this->gravity));

    // This is a workaround for btDynamicsWorld::setInternalTickCallback().
    botsim::BulletEnvironment::tickCallbackPointerMap[this->dynamicsWorld] = this;

    // setInternalTickCallback() attachs a callback for internal ticks (substeps).
    // Only one callback can be attached (this is not an "observer pattern").
    // See: http://bulletphysics.org/mediawiki-1.5.8/index.php/Simulation_Tick_Callbacks
    this->dynamicsWorld->setInternalTickCallback(botsim::BulletEnvironment::tickCallback);

    // Add rigid bodies ///////////////

    // Objects
    std::set<botsim::Object *>::iterator object_it;
    std::set<botsim::Part *>::iterator part_it;
    std::set<botsim::Joint *>::iterator joint_it;
    std::set<botsim::Actuator *>::iterator actuator_it;

    for(object_it = this->objectSet.begin() ; object_it != this->objectSet.end() ; object_it++) {
        std::set<botsim::Part *> part_set = (*object_it)->getPartSet();

        /*
         * Directly adding object's parts to this->dynamicsWorld from here is
         * probably a bad idea:
         * - there are a risk to have the same part multiple times in
         *   this->ObjectSet and this->partSet;
         * - requires to update other modules like osgEnvironment (requires to
         *   add another loop to get objects parts to display for instance).
         * Instead, see the alternative method below.
         */
        //for(part_it = part_set.begin() ; part_it != part_set.end() ; part_it++) {
        //    this->dynamicsWorld->addRigidBody((*part_it)->getRigidBody());
        //}

        /*
         * Take each part of the object and add it to this->partSet.
         * This method has multiple advantages:
         * - no risk to have the same part multiple times in this->ObjectSet
         *   and this->partSet ; this->partSet is the only set of parts
         *   considered by bullet, open scene graph, ...
         * - no needs to update other modules like osgEnvironment (no need to
         *   add another loop to get objects parts to display for instance).
         */
        this->partSet.insert(part_set.begin(), part_set.end());

        /*
         * Add object's joints (i.e. Bullet's constraints).
         */
        std::set<botsim::Joint *> joint_set = (*object_it)->getJointSet();
        for(joint_it = joint_set.begin() ; joint_it != joint_set.end() ; joint_it++) {
            this->dynamicsWorld->addConstraint((*joint_it)->getBulletTypedConstraint());
        }

        /*
         * Add object's actuators (i.e. Bullet's constraints).
         */
        std::set<botsim::Actuator *> actuator_set = (*object_it)->getActuatorSet();
        for(actuator_it = actuator_set.begin() ; actuator_it != actuator_set.end() ; actuator_it++) {
            this->dynamicsWorld->addConstraint((*actuator_it)->getBulletTypedConstraint());
        }
    }

    // Parts
    for(part_it = this->partSet.begin() ; part_it != this->partSet.end() ; part_it++) {
        //std::cout << "Add " << (*part_it)->getName() << std::endl;
        this->dynamicsWorld->addRigidBody((*part_it)->getRigidBody());
    }

    // Start the user clock
    this->userStartTime = std::chrono::system_clock::now();

    // Init the simulation clock
    this->elapsedSimulationTimeSec = 0.;
    this->elapsedSimulationTimeSecTickRes = 0.;
}

botsim::BulletEnvironment::~BulletEnvironment() {
    botsim::BulletEnvironment::tickCallbackPointerMap.erase(this->dynamicsWorld);

    delete this->dynamicsWorld;

    delete this->constraintSolver;
    delete this->collisionConfiguration;
    delete this->collisionDispatcher;
    delete this->broadphase;
}

btDiscreteDynamicsWorld * botsim::BulletEnvironment::getDynamicsWorld() const {
    return this->dynamicsWorld;
}

/**
 *
 */
void botsim::BulletEnvironment::run() {

    // Check some variables ///////////////////////////////

    // assert this->getBulletTimeStepDurationSec() > 0.
    if(this->getBulletTimeStepDurationSec() <= 0.) {
        throw std::invalid_argument("BulletEnvironment::bulletTimeStepDurationSec received a negative value. Within \"healless\" mode, this variable must receive a positive value.");
    }

    // assert this->getSimulationDurationSec() > 0.
    if(this->getSimulationDurationSec() <= 0.) {
        throw std::invalid_argument("BulletEnvironment::simulationDurationSec received a negative value. Within \"healless\" mode, this variable must receive a positive value.");
    }

    // Main loop (simulation loop) ////////////////////////

    while( this->getElapsedSimulationTimeSec() < this->getSimulationDurationSec() ) {
        // Update the physics
        this->stepSimulation(this->getBulletTimeStepDurationSec());
    }
}

/**
 *
 */
void botsim::BulletEnvironment::stepSimulation(const double time_step_duration_sec) {
    this->elapsedSimulationTimeSec += time_step_duration_sec;

    btScalar bullet_time_step_duration_sec = btScalar(time_step_duration_sec);
    btScalar bullet_tick_duration_sec = this->bulletTickDurationSec;
    int bullet_max_ticks_per_time_step = this->bulletMaxTicksPerTimeStep;

    // Warn the user if timeStepDuration > maxTicksPerTimeStep * tickDuration
    // cf. http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World
    if(bullet_time_step_duration_sec > (bullet_max_ticks_per_time_step * bullet_tick_duration_sec)) {
        std::cerr << "Warning: simulation time will be lost (timeStepDuration > maxTicksPerTimeStep * tickDuration)" << std::endl; // TODO: improve this message...
    }

    /*
     * getDynamicsWorld()->stepSimulation()
     * (cf. http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World)
     *
     * The first parameter is the easy one. It's simply the amount of time to
     * step the simulation by. Typically you're going to be passing it the time
     * since you last called it
     *
     * Bullet maintains an internal clock, in order to keep the actual length
     * of ticks constant. This is pivotally important for framerate
     * independence. The third parameter is the size of that internal step.
     *
     * The second parameter is the maximum number of steps that Bullet is
     * allowed to take each time you call it. If you pass a very large timeStep
     * as the first parameter [say, five times the size of the fixed internal
     * time step], then you must increase the number of maxTicksPerTimeStep to
     * compensate for this, otherwise your simulation is "losing" time.
     */
    this->getDynamicsWorld()->stepSimulation(bullet_time_step_duration_sec, bullet_max_ticks_per_time_step, bullet_tick_duration_sec);

    this->notifyTimeStep();
}

/**
 * Realtime case.
 */
void botsim::BulletEnvironment::stepSimulation() {
    // Define the static variable previous_user_time: the previous actual user time (i.e. outside the simulation).
    static std::chrono::time_point<std::chrono::system_clock> previous_user_time = std::chrono::system_clock::now();

    // Get the elapsed user time (in seconds) since the previous time step.
    std::chrono::time_point<std::chrono::system_clock> current_user_time = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds_since_previous_step = current_user_time - previous_user_time;
    double time_step_duration_sec = elapsed_seconds_since_previous_step.count();

    // Update previous_user_time
    previous_user_time = std::chrono::system_clock::now();

    // Step simulation
    this->stepSimulation(time_step_duration_sec);
}

void botsim::BulletEnvironment::resetSimulation() {
    std::cout << "Reset simulation" << std::endl;

    // TODO

    //this->constraintSolver->reset();
    //this->dynamicsWorld->clearForces();
    //this->broadphase->resetPool(this->collisionDispatcher);
    ////m_clock.reset();

    //btOverlappingPairCache* pair_cache = this->dynamicsWorld->getBroadphase()->getOverlappingPairCache();
    //btBroadphasePairArray& pair_array = pair_cache->getOverlappingPairArray();
    //for(int i = 0; i < pair_array.size(); i++) {
    //    pair_cache->cleanOverlappingPair(pair_array[i], this->dynamicsWorld->getDispatcher());
    //}
    // TODO: reset the initial position, angle, velocity, mass, ... of each parts.
}

void botsim::BulletEnvironment::attachTickObserver(botsim::BulletTickObserver * p_observer) {
    this->tickObserverSet.insert(p_observer);
}

void botsim::BulletEnvironment::detachTickObserver(botsim::BulletTickObserver * p_observer) {
    this->tickObserverSet.erase(p_observer);
}

void botsim::BulletEnvironment::attachTimeStepObserver(botsim::TimeStepObserver * p_observer) {
    this->timeStepObserverSet.insert(p_observer);
}

void botsim::BulletEnvironment::detachTimeStepObserver(botsim::TimeStepObserver * p_observer) {
    this->timeStepObserverSet.erase(p_observer);
}

void botsim::BulletEnvironment::notifyTick() {

    // Udate elapsedSimulationTimeSecTickRes
    this->elapsedSimulationTimeSecTickRes += this->bulletTickDurationSec;

    // Update all observers
    std::set<botsim::BulletTickObserver *>::iterator it;
    for(it = this->tickObserverSet.begin() ; it != this->tickObserverSet.end() ; it++) {
        (*it)->update(this);
    }

    // Update each controller
    std::set<botsim::Controller *>::iterator controller_it;
    for(controller_it = this->controllerSet.begin() ; controller_it != this->controllerSet.end() ; controller_it++) {
        (*controller_it)->updateActuators();
    }
}

void botsim::BulletEnvironment::notifyTimeStep() {
    std::set<botsim::TimeStepObserver *>::iterator it;
    for(it = this->timeStepObserverSet.begin() ; it != this->timeStepObserverSet.end() ; it++) {
        (*it)->update(this);
    }
}

/**
 * return the simulation time (i.e. the time within the simulation) elapsed
 * since the beginning of the simulation.
 */
double botsim::BulletEnvironment::getElapsedSimulationTimeSec() const {
    return this->elapsedSimulationTimeSec;
}

/**
 * return the simulation time (i.e. the time within the simulation) elapsed
 * since the beginning of the simulation.
 */
double botsim::BulletEnvironment::getElapsedSimulationTimeSecTickRes() const {
    return this->elapsedSimulationTimeSecTickRes;
}

/**
 * return the actual time (i.e. the time outside the simulation) elapsed since
 * the beginning of the simulation.
 */
double botsim::BulletEnvironment::getElapsedUserTimeSec() const {
    std::chrono::time_point<std::chrono::system_clock> current_user_time = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = current_user_time - this->userStartTime;
    return elapsed_seconds.count();
}

/**
 *
 */
double botsim::BulletEnvironment::getBulletTimeStepDurationSec() const {
    return this->bulletTimeStepDurationSec;
}

/**
 *
 */
double botsim::BulletEnvironment::getBulletTickDurationSec() const {
    return this->bulletTickDurationSec;
}

/**
 *
 */
double botsim::BulletEnvironment::getBulletMaxTicksPerTimeStep() const {
    return this->bulletMaxTicksPerTimeStep;
}

/**
 *
 */
double botsim::BulletEnvironment::getSimulationDurationSec() const {
    return this->simulationDurationSec;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 *   This file includes macros for validating runtime conditions.
 */

#ifndef CODE_UTILS_HPP_
#define CODE_UTILS_HPP_

#include "openthread-core-config.h"

#include "utils/wrap_stdbool.h"

/**
 * This macro calculates the number of elements in an array.
 *
 * @param[in] aArray  Name of the array variable.
 *
 * @returns Number of elements in the array.
 *
 */
#define OT_ARRAY_LENGTH(aArray) (sizeof(aArray) / sizeof(aArray[0]))

/**
 * This macro returns a pointer aligned by @p aAlignment.
 *
 * @param[in] aPointer      A pointer to contiguous space.
 * @param[in] aAlignment    The desired alignment.
 *
 * @returns The aligned pointer.
 *
 */
#define otALIGN(aPointer, aAlignment) ((void *)(((uintptr_t)(aPointer) + (aAlignment)-1U) & ~((aAlignment)-1U)))

// Calculates the aligned variable size.
#define otALIGNED_VAR_SIZE(size, align_type) (((size) + (sizeof(align_type) - 1)) / sizeof(align_type))

// Allocate the structure using "raw" storage.
#define otDEFINE_ALIGNED_VAR(name, size, align_type) \
    align_type name[(((size) + (sizeof(align_type) - 1)) / sizeof(align_type))]

/**
 * This macro checks for the specified status, which is expected to commonly be successful, and branches to the local
 * label 'exit' if the status is unsuccessful.
 *
 *  @param[in]  aStatus     A scalar status to be evaluated against zero (0).
 *
 */
#define SuccessOrExit(aStatus) \
    do                         \
    {                          \
        if ((aStatus) != 0)    \
        {                      \
            goto exit;         \
        }                      \
    } while (false)

/**
 * This macro checks for the specified condition, which is expected to commonly be true, and both executes @a ... and
 * branches to the local label 'exit' if the condition is false.
 *
 *  @param[in]  aCondition  A Boolean expression to be evaluated.
 *  @param[in]  ...         An expression or block to execute when the assertion fails.
 *
 */
#define VerifyOrExit(aCondition, ...) \
    do                                \
    {                                 \
        if (!(aCondition))            \
        {                             \
            __VA_ARGS__;              \
            goto exit;                \
        }                             \
    } while (false)

/**
 * This macro unconditionally executes @a ... and branches to the local label 'exit'.
 *
 * @note The use of this interface implies neither success nor failure for the overall exit status of the enclosing
 *       function body.
 *
 * @param[in]  ...         An optional expression or block to execute when the assertion fails.
 *
 */
#define ExitNow(...) \
    do               \
    {                \
        __VA_ARGS__; \
        goto exit;   \
    } while (false)

/*
 * This macro executes the `statement` and ignores the return value.
 *
 * This is primarily used to indicate the intention of developer that the return value of a function/method can be
 * safely ignored.
 *
 * @param[in]  aStatement  The function/method to execute.
 *
 */
#define IgnoreReturnValue(aStatement) \
    do                                \
    {                                 \
        if (aStatement)               \
        {                             \
        }                             \
    } while (false)

#endif // CODE_UTILS_HPP_
<commit_msg>[code-utils] fix wrong pointer size in otALIGN (#3468)<commit_after>/*
 *  Copyright (c) 2016, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 *   This file includes macros for validating runtime conditions.
 */

#ifndef CODE_UTILS_HPP_
#define CODE_UTILS_HPP_

#include "openthread-core-config.h"

#include "utils/wrap_stdbool.h"

/**
 * This macro calculates the number of elements in an array.
 *
 * @param[in] aArray  Name of the array variable.
 *
 * @returns Number of elements in the array.
 *
 */
#define OT_ARRAY_LENGTH(aArray) (sizeof(aArray) / sizeof(aArray[0]))

/**
 * This macro returns a pointer aligned by @p aAlignment.
 *
 * @param[in] aPointer      A pointer to contiguous space.
 * @param[in] aAlignment    The desired alignment.
 *
 * @returns The aligned pointer.
 *
 */
#define otALIGN(aPointer, aAlignment) \
    ((void *)(((uintptr_t)(aPointer) + (aAlignment)-1UL) & ~((uintptr_t)(aAlignment)-1UL)))

// Calculates the aligned variable size.
#define otALIGNED_VAR_SIZE(size, align_type) (((size) + (sizeof(align_type) - 1)) / sizeof(align_type))

// Allocate the structure using "raw" storage.
#define otDEFINE_ALIGNED_VAR(name, size, align_type) \
    align_type name[(((size) + (sizeof(align_type) - 1)) / sizeof(align_type))]

/**
 * This macro checks for the specified status, which is expected to commonly be successful, and branches to the local
 * label 'exit' if the status is unsuccessful.
 *
 *  @param[in]  aStatus     A scalar status to be evaluated against zero (0).
 *
 */
#define SuccessOrExit(aStatus) \
    do                         \
    {                          \
        if ((aStatus) != 0)    \
        {                      \
            goto exit;         \
        }                      \
    } while (false)

/**
 * This macro checks for the specified condition, which is expected to commonly be true, and both executes @a ... and
 * branches to the local label 'exit' if the condition is false.
 *
 *  @param[in]  aCondition  A Boolean expression to be evaluated.
 *  @param[in]  ...         An expression or block to execute when the assertion fails.
 *
 */
#define VerifyOrExit(aCondition, ...) \
    do                                \
    {                                 \
        if (!(aCondition))            \
        {                             \
            __VA_ARGS__;              \
            goto exit;                \
        }                             \
    } while (false)

/**
 * This macro unconditionally executes @a ... and branches to the local label 'exit'.
 *
 * @note The use of this interface implies neither success nor failure for the overall exit status of the enclosing
 *       function body.
 *
 * @param[in]  ...         An optional expression or block to execute when the assertion fails.
 *
 */
#define ExitNow(...) \
    do               \
    {                \
        __VA_ARGS__; \
        goto exit;   \
    } while (false)

/*
 * This macro executes the `statement` and ignores the return value.
 *
 * This is primarily used to indicate the intention of developer that the return value of a function/method can be
 * safely ignored.
 *
 * @param[in]  aStatement  The function/method to execute.
 *
 */
#define IgnoreReturnValue(aStatement) \
    do                                \
    {                                 \
        if (aStatement)               \
        {                             \
        }                             \
    } while (false)

#endif // CODE_UTILS_HPP_
<|endoftext|>