<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/menu_gtk.h"

#include "app/gfx/gtk_util.h"
#include "app/l10n_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "chrome/browser/gtk/standard_menus.h"
#include "chrome/common/gtk_util.h"
#include "third_party/skia/include/core/SkBitmap.h"

using gtk_util::ConvertAcceleratorsFromWindowsStyle;

bool MenuGtk::block_activation_ = false;

MenuGtk::MenuGtk(MenuGtk::Delegate* delegate,
                 const MenuCreateMaterial* menu_data,
                 GtkAccelGroup* accel_group)
    : delegate_(delegate),
      dummy_accel_group_(gtk_accel_group_new()),
      menu_(gtk_menu_new()),
      factory_(this) {
  ConnectSignalHandlers();
  BuildMenuIn(menu_.get(), menu_data, accel_group);
}

MenuGtk::MenuGtk(MenuGtk::Delegate* delegate, bool load)
    : delegate_(delegate),
      dummy_accel_group_(NULL),
      menu_(gtk_menu_new()),
      factory_(this) {
  ConnectSignalHandlers();
  if (load)
    BuildMenuFromDelegate();
}

MenuGtk::~MenuGtk() {
  menu_.Destroy();
  STLDeleteContainerPointers(submenus_we_own_.begin(), submenus_we_own_.end());
  if (dummy_accel_group_)
    g_object_unref(dummy_accel_group_);
}

void MenuGtk::ConnectSignalHandlers() {
  // We connect afterwards because OnMenuShow calls SetMenuItemInfo, which may
  // take a long time or even start a nested message loop.
  g_signal_connect(menu_.get(), "show", G_CALLBACK(OnMenuShow), this);
  g_signal_connect(menu_.get(), "hide", G_CALLBACK(OnMenuHidden), this);
}

void MenuGtk::AppendMenuItemWithLabel(int command_id,
                                      const std::string& label) {
  std::string converted_label = ConvertAcceleratorsFromWindowsStyle(label);
  GtkWidget* menu_item =
      gtk_menu_item_new_with_mnemonic(converted_label.c_str());
  AppendMenuItem(command_id, menu_item);
}

void MenuGtk::AppendMenuItemWithIcon(int command_id,
                                     const std::string& label,
                                     const SkBitmap& icon) {
  GtkWidget* menu_item = BuildMenuItemWithImage(label, icon);
  AppendMenuItem(command_id, menu_item);
}

void MenuGtk::AppendCheckMenuItemWithLabel(int command_id,
                                           const std::string& label) {
  std::string converted_label = ConvertAcceleratorsFromWindowsStyle(label);
  GtkWidget* menu_item =
      gtk_check_menu_item_new_with_mnemonic(converted_label.c_str());
  AppendMenuItem(command_id, menu_item);
}

void MenuGtk::AppendSeparator() {
  GtkWidget* menu_item = gtk_separator_menu_item_new();
  gtk_widget_show(menu_item);
  gtk_menu_shell_append(GTK_MENU_SHELL(menu_.get()), menu_item);
}

void MenuGtk::AppendMenuItem(int command_id, GtkWidget* menu_item) {
  g_object_set_data(G_OBJECT(menu_item), "menu-id",
                    reinterpret_cast<void*>(command_id));

  g_signal_connect(G_OBJECT(menu_item), "activate",
                   G_CALLBACK(OnMenuItemActivated), this);

  gtk_widget_show(menu_item);
  gtk_menu_shell_append(GTK_MENU_SHELL(menu_.get()), menu_item);
}

void MenuGtk::Popup(GtkWidget* widget, GdkEvent* event) {
  DCHECK(event->type == GDK_BUTTON_PRESS)
      << "Non-button press event sent to RunMenuAt";

  GdkEventButton* event_button = reinterpret_cast<GdkEventButton*>(event);
  Popup(widget, event_button->button, event_button->time);
}

void MenuGtk::Popup(GtkWidget* widget, gint button_type, guint32 timestamp) {
  gtk_menu_popup(GTK_MENU(menu_.get()), NULL, NULL,
                 WidgetMenuPositionFunc,
                 widget,
                 button_type, timestamp);
}

void MenuGtk::PopupAsContext(guint32 event_time) {
  // TODO(estade): |button| value of 3 (6th argument) is not strictly true,
  // but does it matter?
  gtk_menu_popup(GTK_MENU(menu_.get()), NULL, NULL, NULL, NULL, 3, event_time);
}

void MenuGtk::PopupAsContextAt(guint32 event_time, gfx::Point point) {
  gtk_menu_popup(GTK_MENU(menu_.get()), NULL, NULL,
                 PointMenuPositionFunc, &point, 3, event_time);
}

void MenuGtk::PopupAsFromKeyEvent(GtkWidget* widget) {
  Popup(widget, 0, gtk_get_current_event_time());
  gtk_menu_shell_select_first(GTK_MENU_SHELL(menu_.get()), FALSE);
}

void MenuGtk::Cancel() {
  gtk_menu_popdown(GTK_MENU(menu_.get()));
}

void MenuGtk::BuildMenuIn(GtkWidget* menu,
                          const MenuCreateMaterial* menu_data,
                          GtkAccelGroup* accel_group) {
  // We keep track of the last menu item in order to group radio items.
  GtkWidget* last_menu_item = NULL;
  for (; menu_data->type != MENU_END; ++menu_data) {
    GtkWidget* menu_item = NULL;

    std::string label;
    if (menu_data->label_argument) {
      label = l10n_util::GetStringFUTF8(
          menu_data->label_id,
          l10n_util::GetStringUTF16(menu_data->label_argument));
    } else if (menu_data->label_id) {
      label = l10n_util::GetStringUTF8(menu_data->label_id);
    } else if (menu_data->type != MENU_SEPARATOR) {
      label = delegate_->GetLabel(menu_data->id);
      DCHECK(!label.empty());
    }

    label = ConvertAcceleratorsFromWindowsStyle(label);

    switch (menu_data->type) {
      case MENU_RADIO:
        if (GTK_IS_RADIO_MENU_ITEM(last_menu_item)) {
          menu_item = gtk_radio_menu_item_new_with_mnemonic_from_widget(
              GTK_RADIO_MENU_ITEM(last_menu_item), label.c_str());
        } else {
          menu_item = gtk_radio_menu_item_new_with_mnemonic(
              NULL, label.c_str());
        }
        break;
      case MENU_CHECKBOX:
        menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
        break;
      case MENU_SEPARATOR:
        menu_item = gtk_separator_menu_item_new();
        break;
      case MENU_NORMAL:
      default:
        menu_item = gtk_menu_item_new_with_mnemonic(label.c_str());
        break;
    }

    if (menu_data->submenu) {
      GtkWidget* submenu = gtk_menu_new();
      BuildMenuIn(submenu, menu_data->submenu, accel_group);
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
    } else if (menu_data->custom_submenu) {
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
                                menu_data->custom_submenu->menu_.get());
      submenus_we_own_.push_back(menu_data->custom_submenu);
    }

    if (menu_data->accel_key) {
      // If we ever want to let the user do any key remaping, we'll need to
      // change the following so we make a gtk_accel_map which keeps the actual
      // keys.
      gtk_widget_add_accelerator(menu_item,
                                 "activate",
                                 menu_data->only_show || !accel_group ?
                                     dummy_accel_group_ : accel_group,
                                 menu_data->accel_key,
                                 GdkModifierType(menu_data->accel_modifiers),
                                 GTK_ACCEL_VISIBLE);
    }

    g_object_set_data(G_OBJECT(menu_item), "menu-data",
                      const_cast<MenuCreateMaterial*>(menu_data));

    g_signal_connect(G_OBJECT(menu_item), "activate",
                     G_CALLBACK(OnMenuItemActivated), this);

    gtk_widget_show(menu_item);
    gtk_menu_append(menu, menu_item);
    last_menu_item = menu_item;
  }
}

GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
                                           const SkBitmap& icon) {
  std::string converted_label = ConvertAcceleratorsFromWindowsStyle(label);
  GtkWidget* menu_item =
      gtk_image_menu_item_new_with_mnemonic(converted_label.c_str());

  GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
                                gtk_image_new_from_pixbuf(pixbuf));
  g_object_unref(pixbuf);
  if (delegate_->AlwaysShowImages())
    gtk_util::SetAlwaysShowImage(menu_item);

  return menu_item;
}

void MenuGtk::BuildMenuFromDelegate() {
  // Note that the menu IDs start at 1, not 0.
  for (int i = 1; i <= delegate_->GetItemCount(); ++i) {
    GtkWidget* menu_item = NULL;

    if (delegate_->IsItemSeparator(i)) {
      menu_item = gtk_separator_menu_item_new();
    } else if (delegate_->HasIcon(i)) {
      const SkBitmap* icon = delegate_->GetIcon(i);
      menu_item = BuildMenuItemWithImage(delegate_->GetLabel(i), *icon);
    } else {
      menu_item = gtk_menu_item_new_with_label(delegate_->GetLabel(i).c_str());
    }

    AppendMenuItem(i, menu_item);
  }
}

// static
void MenuGtk::OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu) {
  if (block_activation_)
    return;

  // We receive activation messages when highlighting a menu that has a
  // submenu. Ignore them.
  if (gtk_menu_item_get_submenu(menuitem))
    return;

  const MenuCreateMaterial* data =
      reinterpret_cast<const MenuCreateMaterial*>(
          g_object_get_data(G_OBJECT(menuitem), "menu-data"));

  int id;
  if (data) {
    id = data->id;
  } else {
    id = reinterpret_cast<intptr_t>(g_object_get_data(G_OBJECT(menuitem),
                                                      "menu-id"));
  }

  // The menu item can still be activated by hotkeys even if it is disabled.
  if (menu->delegate_->IsCommandEnabled(id))
    menu->delegate_->ExecuteCommand(id);
}

// static
void MenuGtk::WidgetMenuPositionFunc(GtkMenu* menu,
                                     int* x,
                                     int* y,
                                     gboolean* push_in,
                                     void* void_widget) {
  GtkWidget* widget = GTK_WIDGET(void_widget);
  GtkRequisition menu_req;

  gtk_widget_size_request(GTK_WIDGET(menu), &menu_req);

  gdk_window_get_origin(widget->window, x, y);
  GdkScreen *screen = gtk_widget_get_screen(widget);
  gint monitor = gdk_screen_get_monitor_at_point(screen, *x, *y);

  GdkRectangle screen_rect;
  gdk_screen_get_monitor_geometry(screen, monitor,
                                  &screen_rect);

  if (GTK_WIDGET_NO_WINDOW(widget)) {
    *x += widget->allocation.x;
    *y += widget->allocation.y;
  }
  *y += widget->allocation.height;

  bool start_align =
    !!g_object_get_data(G_OBJECT(widget), "left-align-popup");
  if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
    start_align = !start_align;

  if (!start_align)
    *x += widget->allocation.width - menu_req.width;

  // If the menu would run off the bottom of the screen, and there is more
  // screen space up than down, then pop upwards.
  if (*y + menu_req.height >= screen_rect.height &&
      *y > screen_rect.height / 2) {
    *y -= menu_req.height;
  }

  *push_in = FALSE;
}

// static
void MenuGtk::PointMenuPositionFunc(GtkMenu* menu,
                                    int* x,
                                    int* y,
                                    gboolean* push_in,
                                    gpointer userdata) {
  *push_in = TRUE;

  gfx::Point* point = reinterpret_cast<gfx::Point*>(userdata);
  *x = point->x();
  *y = point->y();
}

void MenuGtk::UpdateMenu() {
  gtk_container_foreach(GTK_CONTAINER(menu_.get()), SetMenuItemInfo, this);
}

// static
void MenuGtk::OnMenuShow(GtkWidget* widget, MenuGtk* menu) {
  MessageLoop::current()->PostTask(FROM_HERE,
      menu->factory_.NewRunnableMethod(&MenuGtk::UpdateMenu));
}

// static
void MenuGtk::OnMenuHidden(GtkWidget* widget, MenuGtk* menu) {
  menu->delegate_->StoppedShowing();
}

// static
void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) {
  if (GTK_IS_SEPARATOR_MENU_ITEM(widget)) {
    // We need to explicitly handle this case because otherwise we'll ask the
    // menu delegate about something with an invalid id.
    return;
  }

  MenuGtk* menu = reinterpret_cast<MenuGtk*>(userdata);
  int id;
  const MenuCreateMaterial* data =
      reinterpret_cast<const MenuCreateMaterial*>(
          g_object_get_data(G_OBJECT(widget), "menu-data"));
  if (data) {
    id = data->id;
  } else {
    id = reinterpret_cast<intptr_t>(g_object_get_data(G_OBJECT(widget),
                                    "menu-id"));
  }

  if (GTK_IS_CHECK_MENU_ITEM(widget)) {
    GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(widget);

    // gtk_check_menu_item_set_active() will send the activate signal. Touching
    // the underlying "active" property will also call the "activate" handler
    // for this menu item. So we prevent the "activate" handler from
    // being called while we set the checkbox.
    // Why not use one of the glib signal-blocking functions?  Because when we
    // toggle a radio button, it will deactivate one of the other radio buttons,
    // which we don't have a pointer to.
    // Wny not make this a member variable?  Because "menu" is a pointer to the
    // root of the MenuGtk and we want to disable *all* MenuGtks, including
    // submenus.
    block_activation_ = true;
    gtk_check_menu_item_set_active(item, menu->delegate_->IsItemChecked(id));
    block_activation_ = false;
  }

  if (GTK_IS_MENU_ITEM(widget)) {
    gtk_widget_set_sensitive(
        widget, menu->delegate_->IsCommandEnabled(id));

    GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
    if (submenu) {
      gtk_container_foreach(GTK_CONTAINER(submenu), &SetMenuItemInfo,
                            userdata);
    }
  }
}
<commit_msg>GTK: Fix popup menu positioning.<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/menu_gtk.h"

#include "app/gfx/gtk_util.h"
#include "app/l10n_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "chrome/browser/gtk/standard_menus.h"
#include "chrome/common/gtk_util.h"
#include "third_party/skia/include/core/SkBitmap.h"

using gtk_util::ConvertAcceleratorsFromWindowsStyle;

bool MenuGtk::block_activation_ = false;

MenuGtk::MenuGtk(MenuGtk::Delegate* delegate,
                 const MenuCreateMaterial* menu_data,
                 GtkAccelGroup* accel_group)
    : delegate_(delegate),
      dummy_accel_group_(gtk_accel_group_new()),
      menu_(gtk_menu_new()),
      factory_(this) {
  ConnectSignalHandlers();
  BuildMenuIn(menu_.get(), menu_data, accel_group);
}

MenuGtk::MenuGtk(MenuGtk::Delegate* delegate, bool load)
    : delegate_(delegate),
      dummy_accel_group_(NULL),
      menu_(gtk_menu_new()),
      factory_(this) {
  ConnectSignalHandlers();
  if (load)
    BuildMenuFromDelegate();
}

MenuGtk::~MenuGtk() {
  menu_.Destroy();
  STLDeleteContainerPointers(submenus_we_own_.begin(), submenus_we_own_.end());
  if (dummy_accel_group_)
    g_object_unref(dummy_accel_group_);
}

void MenuGtk::ConnectSignalHandlers() {
  // We connect afterwards because OnMenuShow calls SetMenuItemInfo, which may
  // take a long time or even start a nested message loop.
  g_signal_connect(menu_.get(), "show", G_CALLBACK(OnMenuShow), this);
  g_signal_connect(menu_.get(), "hide", G_CALLBACK(OnMenuHidden), this);
}

void MenuGtk::AppendMenuItemWithLabel(int command_id,
                                      const std::string& label) {
  std::string converted_label = ConvertAcceleratorsFromWindowsStyle(label);
  GtkWidget* menu_item =
      gtk_menu_item_new_with_mnemonic(converted_label.c_str());
  AppendMenuItem(command_id, menu_item);
}

void MenuGtk::AppendMenuItemWithIcon(int command_id,
                                     const std::string& label,
                                     const SkBitmap& icon) {
  GtkWidget* menu_item = BuildMenuItemWithImage(label, icon);
  AppendMenuItem(command_id, menu_item);
}

void MenuGtk::AppendCheckMenuItemWithLabel(int command_id,
                                           const std::string& label) {
  std::string converted_label = ConvertAcceleratorsFromWindowsStyle(label);
  GtkWidget* menu_item =
      gtk_check_menu_item_new_with_mnemonic(converted_label.c_str());
  AppendMenuItem(command_id, menu_item);
}

void MenuGtk::AppendSeparator() {
  GtkWidget* menu_item = gtk_separator_menu_item_new();
  gtk_widget_show(menu_item);
  gtk_menu_shell_append(GTK_MENU_SHELL(menu_.get()), menu_item);
}

void MenuGtk::AppendMenuItem(int command_id, GtkWidget* menu_item) {
  g_object_set_data(G_OBJECT(menu_item), "menu-id",
                    reinterpret_cast<void*>(command_id));

  g_signal_connect(G_OBJECT(menu_item), "activate",
                   G_CALLBACK(OnMenuItemActivated), this);

  gtk_widget_show(menu_item);
  gtk_menu_shell_append(GTK_MENU_SHELL(menu_.get()), menu_item);
}

void MenuGtk::Popup(GtkWidget* widget, GdkEvent* event) {
  DCHECK(event->type == GDK_BUTTON_PRESS)
      << "Non-button press event sent to RunMenuAt";

  GdkEventButton* event_button = reinterpret_cast<GdkEventButton*>(event);
  Popup(widget, event_button->button, event_button->time);
}

void MenuGtk::Popup(GtkWidget* widget, gint button_type, guint32 timestamp) {
  gtk_menu_popup(GTK_MENU(menu_.get()), NULL, NULL,
                 WidgetMenuPositionFunc,
                 widget,
                 button_type, timestamp);
}

void MenuGtk::PopupAsContext(guint32 event_time) {
  // TODO(estade): |button| value of 3 (6th argument) is not strictly true,
  // but does it matter?
  gtk_menu_popup(GTK_MENU(menu_.get()), NULL, NULL, NULL, NULL, 3, event_time);
}

void MenuGtk::PopupAsContextAt(guint32 event_time, gfx::Point point) {
  gtk_menu_popup(GTK_MENU(menu_.get()), NULL, NULL,
                 PointMenuPositionFunc, &point, 3, event_time);
}

void MenuGtk::PopupAsFromKeyEvent(GtkWidget* widget) {
  Popup(widget, 0, gtk_get_current_event_time());
  gtk_menu_shell_select_first(GTK_MENU_SHELL(menu_.get()), FALSE);
}

void MenuGtk::Cancel() {
  gtk_menu_popdown(GTK_MENU(menu_.get()));
}

void MenuGtk::BuildMenuIn(GtkWidget* menu,
                          const MenuCreateMaterial* menu_data,
                          GtkAccelGroup* accel_group) {
  // We keep track of the last menu item in order to group radio items.
  GtkWidget* last_menu_item = NULL;
  for (; menu_data->type != MENU_END; ++menu_data) {
    GtkWidget* menu_item = NULL;

    std::string label;
    if (menu_data->label_argument) {
      label = l10n_util::GetStringFUTF8(
          menu_data->label_id,
          l10n_util::GetStringUTF16(menu_data->label_argument));
    } else if (menu_data->label_id) {
      label = l10n_util::GetStringUTF8(menu_data->label_id);
    } else if (menu_data->type != MENU_SEPARATOR) {
      label = delegate_->GetLabel(menu_data->id);
      DCHECK(!label.empty());
    }

    label = ConvertAcceleratorsFromWindowsStyle(label);

    switch (menu_data->type) {
      case MENU_RADIO:
        if (GTK_IS_RADIO_MENU_ITEM(last_menu_item)) {
          menu_item = gtk_radio_menu_item_new_with_mnemonic_from_widget(
              GTK_RADIO_MENU_ITEM(last_menu_item), label.c_str());
        } else {
          menu_item = gtk_radio_menu_item_new_with_mnemonic(
              NULL, label.c_str());
        }
        break;
      case MENU_CHECKBOX:
        menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
        break;
      case MENU_SEPARATOR:
        menu_item = gtk_separator_menu_item_new();
        break;
      case MENU_NORMAL:
      default:
        menu_item = gtk_menu_item_new_with_mnemonic(label.c_str());
        break;
    }

    if (menu_data->submenu) {
      GtkWidget* submenu = gtk_menu_new();
      BuildMenuIn(submenu, menu_data->submenu, accel_group);
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
    } else if (menu_data->custom_submenu) {
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
                                menu_data->custom_submenu->menu_.get());
      submenus_we_own_.push_back(menu_data->custom_submenu);
    }

    if (menu_data->accel_key) {
      // If we ever want to let the user do any key remaping, we'll need to
      // change the following so we make a gtk_accel_map which keeps the actual
      // keys.
      gtk_widget_add_accelerator(menu_item,
                                 "activate",
                                 menu_data->only_show || !accel_group ?
                                     dummy_accel_group_ : accel_group,
                                 menu_data->accel_key,
                                 GdkModifierType(menu_data->accel_modifiers),
                                 GTK_ACCEL_VISIBLE);
    }

    g_object_set_data(G_OBJECT(menu_item), "menu-data",
                      const_cast<MenuCreateMaterial*>(menu_data));

    g_signal_connect(G_OBJECT(menu_item), "activate",
                     G_CALLBACK(OnMenuItemActivated), this);

    gtk_widget_show(menu_item);
    gtk_menu_append(menu, menu_item);
    last_menu_item = menu_item;
  }
}

GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
                                           const SkBitmap& icon) {
  std::string converted_label = ConvertAcceleratorsFromWindowsStyle(label);
  GtkWidget* menu_item =
      gtk_image_menu_item_new_with_mnemonic(converted_label.c_str());

  GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
  gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
                                gtk_image_new_from_pixbuf(pixbuf));
  g_object_unref(pixbuf);
  if (delegate_->AlwaysShowImages())
    gtk_util::SetAlwaysShowImage(menu_item);

  return menu_item;
}

void MenuGtk::BuildMenuFromDelegate() {
  // Note that the menu IDs start at 1, not 0.
  for (int i = 1; i <= delegate_->GetItemCount(); ++i) {
    GtkWidget* menu_item = NULL;

    if (delegate_->IsItemSeparator(i)) {
      menu_item = gtk_separator_menu_item_new();
    } else if (delegate_->HasIcon(i)) {
      const SkBitmap* icon = delegate_->GetIcon(i);
      menu_item = BuildMenuItemWithImage(delegate_->GetLabel(i), *icon);
    } else {
      menu_item = gtk_menu_item_new_with_label(delegate_->GetLabel(i).c_str());
    }

    AppendMenuItem(i, menu_item);
  }
}

// static
void MenuGtk::OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu) {
  if (block_activation_)
    return;

  // We receive activation messages when highlighting a menu that has a
  // submenu. Ignore them.
  if (gtk_menu_item_get_submenu(menuitem))
    return;

  const MenuCreateMaterial* data =
      reinterpret_cast<const MenuCreateMaterial*>(
          g_object_get_data(G_OBJECT(menuitem), "menu-data"));

  int id;
  if (data) {
    id = data->id;
  } else {
    id = reinterpret_cast<intptr_t>(g_object_get_data(G_OBJECT(menuitem),
                                                      "menu-id"));
  }

  // The menu item can still be activated by hotkeys even if it is disabled.
  if (menu->delegate_->IsCommandEnabled(id))
    menu->delegate_->ExecuteCommand(id);
}

// static
void MenuGtk::WidgetMenuPositionFunc(GtkMenu* menu,
                                     int* x,
                                     int* y,
                                     gboolean* push_in,
                                     void* void_widget) {
  GtkWidget* widget = GTK_WIDGET(void_widget);
  GtkRequisition menu_req;

  gtk_widget_size_request(GTK_WIDGET(menu), &menu_req);

  gdk_window_get_origin(widget->window, x, y);
  GdkScreen *screen = gtk_widget_get_screen(widget);
  gint monitor = gdk_screen_get_monitor_at_point(screen, *x, *y);

  GdkRectangle screen_rect;
  gdk_screen_get_monitor_geometry(screen, monitor,
                                  &screen_rect);

  if (GTK_WIDGET_NO_WINDOW(widget)) {
    *x += widget->allocation.x;
    *y += widget->allocation.y;
  }
  *y += widget->allocation.height;

  bool start_align =
    !!g_object_get_data(G_OBJECT(widget), "left-align-popup");
  if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
    start_align = !start_align;

  if (!start_align)
    *x += widget->allocation.width - menu_req.width;

  // If the menu would run off the bottom of the screen, and there is more
  // screen space up than down, then pop upwards.
  if (*y + menu_req.height >= screen_rect.height &&
      *y > screen_rect.height / 2) {
    *y -= menu_req.height;
  }

  *push_in = FALSE;
}

// static
void MenuGtk::PointMenuPositionFunc(GtkMenu* menu,
                                    int* x,
                                    int* y,
                                    gboolean* push_in,
                                    gpointer userdata) {
  *push_in = TRUE;

  gfx::Point* point = reinterpret_cast<gfx::Point*>(userdata);
  *x = point->x();
  *y = point->y();

  GtkRequisition menu_req;
  gtk_widget_size_request(GTK_WIDGET(menu), &menu_req);
  GdkScreen* screen = gdk_screen_get_default();
  gint screen_height = gdk_screen_get_height(screen);

  if (*y + menu_req.height >= screen_height)
    *y -= menu_req.height;
}

void MenuGtk::UpdateMenu() {
  gtk_container_foreach(GTK_CONTAINER(menu_.get()), SetMenuItemInfo, this);
}

// static
void MenuGtk::OnMenuShow(GtkWidget* widget, MenuGtk* menu) {
  MessageLoop::current()->PostTask(FROM_HERE,
      menu->factory_.NewRunnableMethod(&MenuGtk::UpdateMenu));
}

// static
void MenuGtk::OnMenuHidden(GtkWidget* widget, MenuGtk* menu) {
  menu->delegate_->StoppedShowing();
}

// static
void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) {
  if (GTK_IS_SEPARATOR_MENU_ITEM(widget)) {
    // We need to explicitly handle this case because otherwise we'll ask the
    // menu delegate about something with an invalid id.
    return;
  }

  MenuGtk* menu = reinterpret_cast<MenuGtk*>(userdata);
  int id;
  const MenuCreateMaterial* data =
      reinterpret_cast<const MenuCreateMaterial*>(
          g_object_get_data(G_OBJECT(widget), "menu-data"));
  if (data) {
    id = data->id;
  } else {
    id = reinterpret_cast<intptr_t>(g_object_get_data(G_OBJECT(widget),
                                    "menu-id"));
  }

  if (GTK_IS_CHECK_MENU_ITEM(widget)) {
    GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(widget);

    // gtk_check_menu_item_set_active() will send the activate signal. Touching
    // the underlying "active" property will also call the "activate" handler
    // for this menu item. So we prevent the "activate" handler from
    // being called while we set the checkbox.
    // Why not use one of the glib signal-blocking functions?  Because when we
    // toggle a radio button, it will deactivate one of the other radio buttons,
    // which we don't have a pointer to.
    // Wny not make this a member variable?  Because "menu" is a pointer to the
    // root of the MenuGtk and we want to disable *all* MenuGtks, including
    // submenus.
    block_activation_ = true;
    gtk_check_menu_item_set_active(item, menu->delegate_->IsItemChecked(id));
    block_activation_ = false;
  }

  if (GTK_IS_MENU_ITEM(widget)) {
    gtk_widget_set_sensitive(
        widget, menu->delegate_->IsCommandEnabled(id));

    GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
    if (submenu) {
      gtk_container_foreach(GTK_CONTAINER(submenu), &SetMenuItemInfo,
                            userdata);
    }
  }
}
<|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/net/referrer.h"

#include "base/logging.h"

namespace chrome_browser_net {

void Referrer::SuggestHost(const std::string& host) {
  // Limit how large our list can get, in case we start make mistakes about
  // what hostnames are in sub-resources (example: Some advertisments have
  // a link to the ad agency, and then provide a "surprising" redirect to
  // the advertised entity, which appears to be a subresource on the page
  // hosting the ad).
  static const size_t kMaxSuggestions = 8;

  if (host.empty())
    return;
  if (kMaxSuggestions <= size()) {
    DeleteLeastUseful();
    DCHECK(kMaxSuggestions > size());
  }
  // Add in the new suggestion.
  (*this)[host];
}

void Referrer::DeleteLeastUseful() {
  std::string least_useful_name;
  // We use longs for durations because we will use multiplication on them.
  int64 least_useful_latency;  // Duration in milliseconds.
  int64 least_useful_lifetime;  // Duration in milliseconds.

  const base::Time kNow(base::Time::Now());  // Avoid multiple calls.
  for (HostNameMap::iterator it = this->begin(); it != this->end(); ++it) {
    int64 lifetime = (kNow - it->second.birth_time()).InMilliseconds();
    int64 latency = it->second.latency().InMilliseconds();
    if (!least_useful_name.empty()) {
      if (!latency && !least_useful_latency) {
        // Older name is less useful.
        if (lifetime <= least_useful_lifetime)
          continue;
      } else {
        // Compare the ratios latency/lifetime vs.
        // least_useful_latency/least_useful_lifetime by cross multiplying (to
        // avoid integer division hassles).  Overflow's won't happen until
        // both latency and lifetime pass about 49 days.
        if (latency * least_useful_lifetime >=
            least_useful_latency * lifetime) {
          continue;
        }
      }
    }
    least_useful_name = it->first;
    least_useful_latency = latency;
    least_useful_lifetime = lifetime;
  }
  erase(least_useful_name);
}

void Referrer::AccrueValue(const base::TimeDelta& delta,
                           const std::string host) {
  DCHECK(this->find(host) != this->end());
  (*this)[host].AccrueValue(delta);
}

}  // namespace chrome_browser_net
<commit_msg>fix linux opt build Set initial values to 0.<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/net/referrer.h"

#include "base/logging.h"

namespace chrome_browser_net {

void Referrer::SuggestHost(const std::string& host) {
  // Limit how large our list can get, in case we start make mistakes about
  // what hostnames are in sub-resources (example: Some advertisments have
  // a link to the ad agency, and then provide a "surprising" redirect to
  // the advertised entity, which appears to be a subresource on the page
  // hosting the ad).
  static const size_t kMaxSuggestions = 8;

  if (host.empty())
    return;
  if (kMaxSuggestions <= size()) {
    DeleteLeastUseful();
    DCHECK(kMaxSuggestions > size());
  }
  // Add in the new suggestion.
  (*this)[host];
}

void Referrer::DeleteLeastUseful() {
  std::string least_useful_name;
  // We use longs for durations because we will use multiplication on them.
  int64 least_useful_latency = 0;  // Duration in milliseconds.
  int64 least_useful_lifetime = 0;  // Duration in milliseconds.

  const base::Time kNow(base::Time::Now());  // Avoid multiple calls.
  for (HostNameMap::iterator it = this->begin(); it != this->end(); ++it) {
    int64 lifetime = (kNow - it->second.birth_time()).InMilliseconds();
    int64 latency = it->second.latency().InMilliseconds();
    if (!least_useful_name.empty()) {
      if (!latency && !least_useful_latency) {
        // Older name is less useful.
        if (lifetime <= least_useful_lifetime)
          continue;
      } else {
        // Compare the ratios latency/lifetime vs.
        // least_useful_latency/least_useful_lifetime by cross multiplying (to
        // avoid integer division hassles).  Overflow's won't happen until
        // both latency and lifetime pass about 49 days.
        if (latency * least_useful_lifetime >=
            least_useful_latency * lifetime) {
          continue;
        }
      }
    }
    least_useful_name = it->first;
    least_useful_latency = latency;
    least_useful_lifetime = lifetime;
  }
  erase(least_useful_name);
}

void Referrer::AccrueValue(const base::TimeDelta& delta,
                           const std::string host) {
  DCHECK(this->find(host) != this->end());
  (*this)[host].AccrueValue(delta);
}

}  // namespace chrome_browser_net
<|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/options_util.h"

#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/host_zoom_map.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/pref_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/installer/util/google_update_settings.h"

// static
void OptionsUtil::ResetToDefaults(Profile* profile) {
  // TODO(tc): It would be nice if we could generate this list automatically so
  // changes to any of the options pages doesn't require updating this list
  // manually.
  PrefService* prefs = profile->GetPrefs();
  const wchar_t* kUserPrefs[] = {
    prefs::kAcceptLanguages,
    prefs::kAlternateErrorPagesEnabled,
    prefs::kClearSiteDataOnExit,
    prefs::kCookieBehavior,
    prefs::kDefaultCharset,
    prefs::kDnsPrefetchingEnabled,
#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
    prefs::kCertRevocationCheckingEnabled,
    prefs::kSSL2Enabled,
    prefs::kSSL3Enabled,
    prefs::kTLS1Enabled,
#endif
#if defined(OS_CHROMEOS)
    prefs::kTimeZone,
    prefs::kTapToClickEnabled,
    prefs::kVertEdgeScrollEnabled,
    prefs::kTouchpadSpeedFactor,
    prefs::kTouchpadSensitivity,
#endif
    prefs::kDownloadDefaultDirectory,
    prefs::kDownloadExtensionsToOpen,
    prefs::kEnableSpellCheck,
    prefs::kAutoFillEnabled,
    prefs::kHomePage,
    prefs::kHomePageIsNewTabPage,
    prefs::kMixedContentFiltering,
    prefs::kPrivacyFilterRules,
    prefs::kPromptForDownload,
    prefs::kPasswordManagerEnabled,
    prefs::kRestoreOnStartup,
    prefs::kSafeBrowsingEnabled,
    prefs::kSearchSuggestEnabled,
    prefs::kShowHomeButton,
    prefs::kSpellCheckDictionary,
    prefs::kURLsToRestoreOnStartup,
    prefs::kWebKitDefaultFixedFontSize,
    prefs::kWebKitDefaultFontSize,
    prefs::kWebKitFixedFontFamily,
    prefs::kWebKitJavaEnabled,
    prefs::kWebKitJavascriptEnabled,
    prefs::kWebKitLoadsImagesAutomatically,
    prefs::kWebKitPluginsEnabled,
    prefs::kWebKitSansSerifFontFamily,
    prefs::kWebKitSerifFontFamily,
  };
  profile->GetDownloadManager()->ResetAutoOpenFiles();
  profile->GetHostContentSettingsMap()->ResetToDefaults();
  profile->GetHostZoomMap()->ResetToDefaults();
  for (size_t i = 0; i < arraysize(kUserPrefs); ++i)
    prefs->ClearPref(kUserPrefs[i]);

  PrefService* local_state = g_browser_process->local_state();
  // Note that we don't reset the kMetricsReportingEnabled preference here
  // because the reset will reset it to the default setting specified in Chrome
  // source, not the default setting selected by the user on the web page where
  // they downloaded Chrome. This means that if the user ever resets their
  // settings they'll either inadvertedly enable this logging or disable it.
  // One is undesirable for them, one is undesirable for us. For now, we just
  // don't reset it.
  const wchar_t* kLocalStatePrefs[] = {
    prefs::kApplicationLocale,
  };
  for (size_t i = 0; i < arraysize(kLocalStatePrefs); ++i)
    local_state->ClearPref(kLocalStatePrefs[i]);
}

// static
bool OptionsUtil::ResolveMetricsReportingEnabled(bool enabled) {
  GoogleUpdateSettings::SetCollectStatsConsent(enabled);
  bool update_pref = GoogleUpdateSettings::GetCollectStatsConsent();

  if (enabled != update_pref) {
    DLOG(INFO) <<
        "OptionsUtil: Unable to set crash report status to " <<
        enabled;
  }

  // Only change the pref if GoogleUpdateSettings::GetCollectStatsConsent
  // succeeds.
  enabled = update_pref;

  MetricsService* metrics = g_browser_process->metrics_service();
  DCHECK(metrics);
  if (metrics) {
    metrics->SetUserPermitsUpload(enabled);
    if (enabled)
      metrics->Start();
    else
      metrics->Stop();
  }

  return enabled;
}
<commit_msg>Make "Reset to Defaults" reset geolocation permissions too<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/options_util.h"

#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/host_zoom_map.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/pref_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/installer/util/google_update_settings.h"

// static
void OptionsUtil::ResetToDefaults(Profile* profile) {
  // TODO(tc): It would be nice if we could generate this list automatically so
  // changes to any of the options pages doesn't require updating this list
  // manually.
  PrefService* prefs = profile->GetPrefs();
  const wchar_t* kUserPrefs[] = {
    prefs::kAcceptLanguages,
    prefs::kAlternateErrorPagesEnabled,
    prefs::kClearSiteDataOnExit,
    prefs::kCookieBehavior,
    prefs::kDefaultCharset,
    prefs::kDnsPrefetchingEnabled,
#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
    prefs::kCertRevocationCheckingEnabled,
    prefs::kSSL2Enabled,
    prefs::kSSL3Enabled,
    prefs::kTLS1Enabled,
#endif
#if defined(OS_CHROMEOS)
    prefs::kTimeZone,
    prefs::kTapToClickEnabled,
    prefs::kVertEdgeScrollEnabled,
    prefs::kTouchpadSpeedFactor,
    prefs::kTouchpadSensitivity,
#endif
    prefs::kDownloadDefaultDirectory,
    prefs::kDownloadExtensionsToOpen,
    prefs::kEnableSpellCheck,
    prefs::kAutoFillEnabled,
    prefs::kHomePage,
    prefs::kHomePageIsNewTabPage,
    prefs::kMixedContentFiltering,
    prefs::kPrivacyFilterRules,
    prefs::kPromptForDownload,
    prefs::kPasswordManagerEnabled,
    prefs::kRestoreOnStartup,
    prefs::kSafeBrowsingEnabled,
    prefs::kSearchSuggestEnabled,
    prefs::kShowHomeButton,
    prefs::kSpellCheckDictionary,
    prefs::kURLsToRestoreOnStartup,
    prefs::kWebKitDefaultFixedFontSize,
    prefs::kWebKitDefaultFontSize,
    prefs::kWebKitFixedFontFamily,
    prefs::kWebKitJavaEnabled,
    prefs::kWebKitJavascriptEnabled,
    prefs::kWebKitLoadsImagesAutomatically,
    prefs::kWebKitPluginsEnabled,
    prefs::kWebKitSansSerifFontFamily,
    prefs::kWebKitSerifFontFamily,
  };
  profile->GetDownloadManager()->ResetAutoOpenFiles();
  profile->GetHostContentSettingsMap()->ResetToDefaults();
  profile->GetGeolocationContentSettingsMap()->ResetToDefault();
  profile->GetHostZoomMap()->ResetToDefaults();
  for (size_t i = 0; i < arraysize(kUserPrefs); ++i)
    prefs->ClearPref(kUserPrefs[i]);

  PrefService* local_state = g_browser_process->local_state();
  // Note that we don't reset the kMetricsReportingEnabled preference here
  // because the reset will reset it to the default setting specified in Chrome
  // source, not the default setting selected by the user on the web page where
  // they downloaded Chrome. This means that if the user ever resets their
  // settings they'll either inadvertedly enable this logging or disable it.
  // One is undesirable for them, one is undesirable for us. For now, we just
  // don't reset it.
  const wchar_t* kLocalStatePrefs[] = {
    prefs::kApplicationLocale,
  };
  for (size_t i = 0; i < arraysize(kLocalStatePrefs); ++i)
    local_state->ClearPref(kLocalStatePrefs[i]);
}

// static
bool OptionsUtil::ResolveMetricsReportingEnabled(bool enabled) {
  GoogleUpdateSettings::SetCollectStatsConsent(enabled);
  bool update_pref = GoogleUpdateSettings::GetCollectStatsConsent();

  if (enabled != update_pref) {
    DLOG(INFO) <<
        "OptionsUtil: Unable to set crash report status to " <<
        enabled;
  }

  // Only change the pref if GoogleUpdateSettings::GetCollectStatsConsent
  // succeeds.
  enabled = update_pref;

  MetricsService* metrics = g_browser_process->metrics_service();
  DCHECK(metrics);
  if (metrics) {
    metrics->SetUserPermitsUpload(enabled);
    if (enabled)
      metrics->Start();
    else
      metrics->Stop();
  }

  return enabled;
}
<|endoftext|>


<commit_before>//
// Copyright (C) 2005-2007 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2004-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 Pingtel Corp.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES
#include <stdlib.h>

// APPLICATION INCLUDES
#include <os/OsConfigDb.h>
#include "sipXmediaFactoryImpl.h"
#include "CpPhoneMediaInterface.h"
#include <sdp/SdpCodec.h>
#include <mp/MpMediaTask.h>
#include <mp/MpMisc.h>
#include <mp/MpCodec.h>
#include <mp/MpCallFlowGraph.h>
#include <mp/dmaTask.h>
#include <mp/MpCodecFactory.h>
#include <sdp/SdpCodecList.h>
#include "mi/CpMediaInterfaceFactoryFactory.h"

#ifdef INCLUDE_RTCP /* [ */
#include <rtcp/RTCManager.h>
#endif /* INCLUDE_RTCP ] */

#ifdef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
#include <mp/NetInTask.h>
#endif

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// GLOBAL FUNCTION

#define MAX_MANAGED_FLOW_GRAPHS           16

// STATIC VARIABLE INITIALIZATIONS
int sipXmediaFactoryImpl::miInstanceCount=0;

CpMediaInterfaceFactory* spFactory = NULL;
int siInstanceCount=0;

#ifndef DISABLE_DEFAULT_PHONE_MEDIA_INTERFACE_FACTORY
extern "C" CpMediaInterfaceFactory* cpDefaultMediaFactoryFactory(OsConfigDb* pConfigDb)
{
    // TODO: Add locking

    if (spFactory == NULL)
    {
        spFactory = new CpMediaInterfaceFactory();
        spFactory->setFactoryImplementation(new sipXmediaFactoryImpl(pConfigDb));
    }
    siInstanceCount++ ;

    // Assert some sane value
    assert(siInstanceCount < 11) ;
    return spFactory;
}

extern "C" CpMediaInterfaceFactory* sipXmediaFactoryFactory(OsConfigDb* pConfigDb)
{
    return(cpDefaultMediaFactoryFactory(pConfigDb));
}
#endif

extern "C" void sipxDestroyMediaFactoryFactory()
{
    // TODO: Add locking

    if (siInstanceCount > 0)
    {
        siInstanceCount-- ;
        if (siInstanceCount == 0)
        {
            if (spFactory)
            {
                delete spFactory ;
                spFactory = NULL ;
            }
        }
    }
}

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
sipXmediaFactoryImpl::sipXmediaFactoryImpl(OsConfigDb* pConfigDb)
{
    int maxFlowGraph = -1 ;
    UtlString strInBandDTMF ;

    if (pConfigDb)
    {
        pConfigDb->get("PHONESET_MAX_ACTIVE_CALLS_ALLOWED", maxFlowGraph) ;
        pConfigDb->get("PHONESET_SEND_INBAND_DTMF", strInBandDTMF) ;
        strInBandDTMF.toUpper() ;

        OsSysLog::add(FAC_MP, PRI_DEBUG,
                      "sipXmediaFactoryImpl::sipXmediaFactoryImpl maxFlowGraph = %d",
                      maxFlowGraph);
    }

    // Max Flow graphs
    if (maxFlowGraph <=0 )
    {
        maxFlowGraph = MAX_MANAGED_FLOW_GRAPHS;
    }

    // Start audio subsystem if still not started.
    if (miInstanceCount == 0)
    {
        mpStartUp(8000, 80, 16*maxFlowGraph, pConfigDb,
                  mnCodecPaths, mpCodecPaths);
    }

    // Should we send inband DTMF by default?
    if (strInBandDTMF.compareTo("DISABLE") == 0)
    {
        MpCallFlowGraph::setInbandDTMF(false) ;
    }
    else
    {
        MpCallFlowGraph::setInbandDTMF(true) ;
    }

    // init the media processing task
    mpMediaTask = MpMediaTask::getMediaTask(maxFlowGraph);

#ifdef INCLUDE_RTCP /* [ */
    mpiRTCPControl = CRTCManager::getRTCPControl();
#endif /* INCLUDE_RTCP ] */

    if (miInstanceCount == 0)
    {
#ifndef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
        mpStartTasks();
#else
        if (OS_SUCCESS != startNetInTask()) {
           OsSysLog::add(FAC_MP, PRI_ERR,
                         "Could not start NetInTask!!");
        }
#endif
    }

    miGain = 7 ;
    ++miInstanceCount;

    // We are missing synchronization -- give the tasks time to start
    OsTask::delay(100) ;
}

// Destructor
sipXmediaFactoryImpl::~sipXmediaFactoryImpl()
{
    // TODO: Shutdown
    --miInstanceCount;
    if (miInstanceCount == 0)
    {
#ifndef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
        mpStopTasks();
#else
        shutdownNetInTask();
#endif
        mpShutdown();
    }
}

/* ============================ MANIPULATORS ============================== */

CpMediaInterface* sipXmediaFactoryImpl::createMediaInterface( const char* publicAddress,
                                                              const char* localAddress,
                                                              int numCodecs,
                                                              SdpCodec* sdpCodecArray[],
                                                              const char* locale,
                                                              int expeditedIpTos,
                                                              const char* szStunServer,
                                                              int iStunPort,
                                                              int iStunKeepAliveSecs,
                                                              const char* szTurnServer,
                                                              int iTurnPort,
                                                              const char* szTurnUsername,
                                                              const char* szTurnPassword,
                                                              int iTurnKeepAlivePeriodSecs,
                                                              UtlBoolean bEnableICE)
{
    return new CpPhoneMediaInterface(this, publicAddress, localAddress,
            numCodecs, sdpCodecArray, locale, expeditedIpTos, szStunServer,
            iStunPort, iStunKeepAliveSecs, szTurnServer, iTurnPort,
            szTurnUsername, szTurnPassword, iTurnKeepAlivePeriodSecs,
            bEnableICE) ;
}

OsStatus sipXmediaFactoryImpl::setSpeakerVolume(int iVolume)
{
    OsStatus rc = OS_SUCCESS ;
    MpCodec_setVolume(iVolume) ;

    return rc ;
}

OsStatus sipXmediaFactoryImpl::setSpeakerDevice(const UtlString& device)
{
    OsStatus rc = OS_SUCCESS ;
    DmaTask::setCallDevice(device.data()) ;
    return rc ;
}

OsStatus sipXmediaFactoryImpl::setMicrophoneGain(int iGain)
{
    OsStatus rc ;

    miGain = iGain ;
    rc = MpCodec_setGain(miGain) ;
    return rc ;
}

OsStatus sipXmediaFactoryImpl::setMicrophoneDevice(const UtlString& device)
{
    OsStatus rc = OS_SUCCESS ;
    DmaTask::setInputDevice(device.data()) ;
#ifdef WIN32
    dmaSignalMicDeviceChange();
#endif
    return rc ;
}

OsStatus sipXmediaFactoryImpl::muteMicrophone(UtlBoolean bMute)
{
    if (bMute)
    {
        MpCodec_setGain(0) ;
    }
    else
    {
        MpCodec_setGain(miGain) ;
    }
    return OS_SUCCESS ;
}

OsStatus sipXmediaFactoryImpl::setAudioAECMode(const MEDIA_AEC_MODE mode)
{
  if (MpCallFlowGraph::setAECMode((FLOWGRAPH_AEC_MODE)mode)) {
    return OS_SUCCESS;
  }else {
    return OS_NOT_SUPPORTED;
  }
}

OsStatus sipXmediaFactoryImpl::enableAGC(UtlBoolean bEnable) {
  if (MpCallFlowGraph::setAGC(bEnable)) {
    return OS_SUCCESS;
  }else {
    return OS_NOT_SUPPORTED;
  }
}

OsStatus sipXmediaFactoryImpl::setAudioNoiseReductionMode(const MEDIA_NOISE_REDUCTION_MODE mode) {
  if (mode == MEDIA_NOISE_REDUCTION_DISABLED) {
    if (MpCallFlowGraph::setAudioNoiseReduction(FALSE)) {
      return OS_SUCCESS;
    }
  } else {
    if (MpCallFlowGraph::setAudioNoiseReduction(TRUE)) {
      return OS_SUCCESS;
    }
  }
  return OS_NOT_SUPPORTED;
}

OsStatus sipXmediaFactoryImpl::buildCodecFactory(SdpCodecList*    pFactory,
                                                 const UtlString& sAudioPreferences,
                                                 const UtlString& sVideoPreferences,
                                                 int videoFormat,
                                                 int* iRejected)
{
    OsStatus rc = OS_FAILED;

    *iRejected = 0;

    if (pFactory)
    {
        pFactory->clearCodecs();

        // If preferred codecs supplied - add them, else add all supported
        // codecs.
        if (sAudioPreferences.length() > 0)
        {
            *iRejected = pFactory->addCodecs(sAudioPreferences);
            OsSysLog::add(FAC_MP, PRI_DEBUG,
                          "sipXmediaFactoryImpl::buildCodecFactory: supported codecs = %s with NumReject %d",
                          sAudioPreferences.data(), *iRejected);

            rc = OS_SUCCESS;
        }
        else
        {
            // Build up the supported codecs
            MpCodecFactory *pCodecFactory = MpCodecFactory::getMpCodecFactory();
            pCodecFactory->addCodecsToList(*pFactory);

            *iRejected = 0;
            rc = OS_SUCCESS;
        }

#ifdef VIDEO // [
        // If preferred codecs supplied - add them, else add all supported
        // codecs.
        if (sVideoPreferences.length() > 0)
        {
            *iRejected = pFactory->addCodecs(sVideoPreferences);
            OsSysLog::add(FAC_MP, PRI_DEBUG,
                          "sipXmediaFactoryImpl::buildCodecFactory: supported codecs = %s with NumReject %d",
                          sVideoPreferences.data(), *iRejected);

            rc = OS_SUCCESS;
        }
        else
        {
            // Build up the supported codecs
            SdpCodec::SdpCodecTypes videoCodecs[] = {};
            const int numVideoCodecs = sizeof(videoCodecs)/sizeof(SdpCodec::SdpCodecTypes);

            *iRejected = pFactory->addCodecs(numVideoCodecs, videoCodecs);
            rc = OS_SUCCESS;
        }
#endif // VIDEO ]

    }

    return rc;
}

OsStatus sipXmediaFactoryImpl::updateVideoPreviewWindow(void* displayContext)
{
    return OS_NOT_SUPPORTED ;
}

/* ============================ ACCESSORS ================================= */

OsStatus sipXmediaFactoryImpl::getSpeakerVolume(int& iVolume) const
{
    OsStatus rc = OS_SUCCESS ;

    iVolume = MpCodec_getVolume() ;
    if (iVolume==-1) {
        rc = OS_FAILED;
        iVolume = 0;
    }
    return rc ;
}

OsStatus sipXmediaFactoryImpl::getSpeakerDevice(UtlString& device) const
{
    OsStatus rc = OS_SUCCESS ;

    device = DmaTask::getCallDevice() ;
    return rc ;
}

OsStatus sipXmediaFactoryImpl::getMicrophoneGain(int& iGain) const
{
    OsStatus rc = OS_SUCCESS ;

    iGain = MpCodec_getGain() ;
    return rc ;
}

OsStatus sipXmediaFactoryImpl::getMicrophoneDevice(UtlString& device) const
{
    OsStatus rc = OS_SUCCESS ;

    device = DmaTask::getMicDevice() ;
    return rc ;
}

OsStatus sipXmediaFactoryImpl::setVideoPreviewDisplay(void* pDisplay)
{
    return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::setVideoQuality(int quality)
{
    return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::setVideoParameters(int bitRate, int frameRate)
{
    return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoQuality(int& quality) const
{
    return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoBitRate(int& bitRate) const
{
    return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoFrameRate(int& frameRate) const
{
    return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getLocalAudioConnectionId(int& connectionId) const
{
    connectionId = -1 ;

    return OS_NOT_SUPPORTED ;

}

/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

/* //////////////////////////// PRIVATE /////////////////////////////////// */

/* ============================ FUNCTIONS ================================= */

<commit_msg>Reformat sipXmediaFactoryImpl code. Logic itself is unchanged.<commit_after>//
// Copyright (C) 2005-2007 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2004-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 Pingtel Corp.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES
#include <stdlib.h>

// APPLICATION INCLUDES
#include <os/OsConfigDb.h>
#include "sipXmediaFactoryImpl.h"
#include "CpPhoneMediaInterface.h"
#include <sdp/SdpCodec.h>
#include <mp/MpMediaTask.h>
#include <mp/MpMisc.h>
#include <mp/MpCodec.h>
#include <mp/MpCallFlowGraph.h>
#include <mp/dmaTask.h>
#include <mp/MpCodecFactory.h>
#include <sdp/SdpCodecList.h>
#include "mi/CpMediaInterfaceFactoryFactory.h"

#ifdef INCLUDE_RTCP /* [ */
#include <rtcp/RTCManager.h>
#endif /* INCLUDE_RTCP ] */

#ifdef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
#include <mp/NetInTask.h>
#endif

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// GLOBAL FUNCTION

#define MAX_MANAGED_FLOW_GRAPHS 16

// STATIC VARIABLE INITIALIZATIONS
int sipXmediaFactoryImpl::miInstanceCount=0;

CpMediaInterfaceFactory* spFactory = NULL;
int siInstanceCount=0;

#ifndef DISABLE_DEFAULT_PHONE_MEDIA_INTERFACE_FACTORY
extern "C" CpMediaInterfaceFactory* cpDefaultMediaFactoryFactory(OsConfigDb* pConfigDb)
{
   // TODO: Add locking

   if (spFactory == NULL)
   {
      spFactory = new CpMediaInterfaceFactory();
      spFactory->setFactoryImplementation(new sipXmediaFactoryImpl(pConfigDb));
   }
   siInstanceCount++;

   // Assert some sane value
   assert(siInstanceCount < 11);
   return spFactory;
}

extern "C" CpMediaInterfaceFactory* sipXmediaFactoryFactory(OsConfigDb* pConfigDb)
{
   return(cpDefaultMediaFactoryFactory(pConfigDb));
}
#endif

extern "C" void sipxDestroyMediaFactoryFactory()
{
   // TODO: Add locking

   if (siInstanceCount > 0)
   {
      siInstanceCount--;
      if (siInstanceCount == 0)
      {
         if (spFactory)
         {
            delete spFactory;
            spFactory = NULL;
         }
      }
   }
}

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
sipXmediaFactoryImpl::sipXmediaFactoryImpl(OsConfigDb* pConfigDb)
{
   int maxFlowGraph = -1;
   UtlString strInBandDTMF;

   if (pConfigDb)
   {
      pConfigDb->get("PHONESET_MAX_ACTIVE_CALLS_ALLOWED", maxFlowGraph);
      pConfigDb->get("PHONESET_SEND_INBAND_DTMF", strInBandDTMF);
      strInBandDTMF.toUpper();

      OsSysLog::add(FAC_MP, PRI_DEBUG,
                    "sipXmediaFactoryImpl::sipXmediaFactoryImpl"
                    " maxFlowGraph = %d",
                    maxFlowGraph);
   }

   // Max Flow graphs
   if (maxFlowGraph <=0 )
   {
      maxFlowGraph = MAX_MANAGED_FLOW_GRAPHS;
   }

   // Start audio subsystem if still not started.
   if (miInstanceCount == 0)
   {
      mpStartUp(8000, 80, 16*maxFlowGraph, pConfigDb,
                mnCodecPaths, mpCodecPaths);
   }

   // Should we send inband DTMF by default?
   if (strInBandDTMF.compareTo("DISABLE") == 0)
   {
      MpCallFlowGraph::setInbandDTMF(false);
   }
   else
   {
      MpCallFlowGraph::setInbandDTMF(true);
   }

   // init the media processing task
   mpMediaTask = MpMediaTask::getMediaTask(maxFlowGraph);

#ifdef INCLUDE_RTCP /* [ */
   mpiRTCPControl = CRTCManager::getRTCPControl();
#endif /* INCLUDE_RTCP ] */

   if (miInstanceCount == 0)
   {
#ifndef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
      mpStartTasks();
#else
      if (OS_SUCCESS != startNetInTask())
      {
         OsSysLog::add(FAC_MP, PRI_ERR, "Could not start NetInTask!!");
      }
#endif
   }

   miGain = 7;
   ++miInstanceCount;

   // We are missing synchronization -- give the tasks time to start
   OsTask::delay(100);
}

// Destructor
sipXmediaFactoryImpl::~sipXmediaFactoryImpl()
{
   // TODO: Shutdown
   --miInstanceCount;
   if (miInstanceCount == 0)
   {
#ifndef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
      mpStopTasks();
#else
      shutdownNetInTask();
#endif
      mpShutdown();
   }
}

/* ============================ MANIPULATORS ============================== */

CpMediaInterface* sipXmediaFactoryImpl::createMediaInterface(const char* publicAddress,
                                                             const char* localAddress,
                                                             int numCodecs,
                                                             SdpCodec* sdpCodecArray[],
                                                             const char* locale,
                                                             int expeditedIpTos,
                                                             const char* szStunServer,
                                                             int iStunPort,
                                                             int iStunKeepAliveSecs,
                                                             const char* szTurnServer,
                                                             int iTurnPort,
                                                             const char* szTurnUsername,
                                                             const char* szTurnPassword,
                                                             int iTurnKeepAlivePeriodSecs,
                                                             UtlBoolean bEnableICE)
{
   return new CpPhoneMediaInterface(this, publicAddress, localAddress,
      numCodecs, sdpCodecArray, locale, expeditedIpTos, szStunServer,
      iStunPort, iStunKeepAliveSecs, szTurnServer, iTurnPort,
      szTurnUsername, szTurnPassword, iTurnKeepAlivePeriodSecs,
      bEnableICE);
}

OsStatus sipXmediaFactoryImpl::setSpeakerVolume(int iVolume)
{
   OsStatus rc = OS_SUCCESS;
   MpCodec_setVolume(iVolume);

   return rc;
}

OsStatus sipXmediaFactoryImpl::setSpeakerDevice(const UtlString& device)
{
   OsStatus rc = OS_SUCCESS;
   DmaTask::setCallDevice(device.data());
   return rc;
}

OsStatus sipXmediaFactoryImpl::setMicrophoneGain(int iGain)
{
   OsStatus rc;

   miGain = iGain;
   rc = MpCodec_setGain(miGain);
   return rc;
}

OsStatus sipXmediaFactoryImpl::setMicrophoneDevice(const UtlString& device)
{
   OsStatus rc = OS_SUCCESS;
   DmaTask::setInputDevice(device.data());
#ifdef WIN32
   dmaSignalMicDeviceChange();
#endif
   return rc;
}

OsStatus sipXmediaFactoryImpl::muteMicrophone(UtlBoolean bMute)
{
   if (bMute)
   {
      MpCodec_setGain(0);
   }
   else
   {
      MpCodec_setGain(miGain);
   }
   return OS_SUCCESS;
}

OsStatus sipXmediaFactoryImpl::setAudioAECMode(const MEDIA_AEC_MODE mode)
{
   if (MpCallFlowGraph::setAECMode((FLOWGRAPH_AEC_MODE)mode))
   {
      return OS_SUCCESS;
   }
   else
   {
      return OS_NOT_SUPPORTED;
   }
}

OsStatus sipXmediaFactoryImpl::enableAGC(UtlBoolean bEnable)
{
   if (MpCallFlowGraph::setAGC(bEnable))
   {
      return OS_SUCCESS;
   }
   else
   {
      return OS_NOT_SUPPORTED;
   }
}

OsStatus sipXmediaFactoryImpl::setAudioNoiseReductionMode(const MEDIA_NOISE_REDUCTION_MODE mode)
{
   if (mode == MEDIA_NOISE_REDUCTION_DISABLED)
   {
      if (MpCallFlowGraph::setAudioNoiseReduction(FALSE))
      {
         return OS_SUCCESS;
      }
   }
   else
   {
      if (MpCallFlowGraph::setAudioNoiseReduction(TRUE))
      {
         return OS_SUCCESS;
      }
   }
   return OS_NOT_SUPPORTED;
}

OsStatus sipXmediaFactoryImpl::buildCodecFactory(SdpCodecList* pFactory,
                                                 const UtlString& sAudioPreferences,
                                                 const UtlString& sVideoPreferences,
                                                 int videoFormat,
                                                 int* iRejected)
{
   OsStatus rc = OS_FAILED;

   *iRejected = 0;

   if (pFactory)
   {
      pFactory->clearCodecs();

      // If preferred codecs supplied - add them, else add all supported
      // codecs.
      if (sAudioPreferences.length() > 0)
      {
         *iRejected = pFactory->addCodecs(sAudioPreferences);
         OsSysLog::add(FAC_MP, PRI_DEBUG,
                       "sipXmediaFactoryImpl::buildCodecFactory: "
                       "supported codecs = %s with NumReject %d",
                       sAudioPreferences.data(), *iRejected);
         rc = OS_SUCCESS;
      }
      else
      {
         // Build up the supported codecs
         MpCodecFactory *pCodecFactory = MpCodecFactory::getMpCodecFactory();
         pCodecFactory->addCodecsToList(*pFactory);

         *iRejected = 0;
         rc = OS_SUCCESS;
      }

#ifdef VIDEO // [
      // If preferred codecs supplied - add them, else add all supported
      // codecs.
      if (sVideoPreferences.length() > 0)
      {
         *iRejected = pFactory->addCodecs(sVideoPreferences);
         OsSysLog::add(FAC_MP, PRI_DEBUG,
                       "sipXmediaFactoryImpl::buildCodecFactory: "
                       "supported codecs = %s with NumReject %d",
                       sVideoPreferences.data(), *iRejected);
         rc = OS_SUCCESS;
      }
      else
      {
         // Build up the supported codecs
         SdpCodec::SdpCodecTypes videoCodecs[] = {};
         const int numVideoCodecs = sizeof(videoCodecs)/sizeof(SdpCodec::SdpCodecTypes);

         *iRejected = pFactory->addCodecs(numVideoCodecs, videoCodecs);
         rc = OS_SUCCESS;
      }
#endif // VIDEO ]
   }
   return rc;
}

OsStatus sipXmediaFactoryImpl::updateVideoPreviewWindow(void* displayContext)
{
   return OS_NOT_SUPPORTED;
}

/* ============================ ACCESSORS ================================= */

OsStatus sipXmediaFactoryImpl::getSpeakerVolume(int& iVolume) const
{
   OsStatus rc = OS_SUCCESS;

   iVolume = MpCodec_getVolume();
   if (iVolume==-1)
   {
      rc = OS_FAILED;
      iVolume = 0;
   }
   return rc;
}

OsStatus sipXmediaFactoryImpl::getSpeakerDevice(UtlString& device) const
{
   OsStatus rc = OS_SUCCESS;
   device = DmaTask::getCallDevice();
   return rc;
}

OsStatus sipXmediaFactoryImpl::getMicrophoneGain(int& iGain) const
{
   OsStatus rc = OS_SUCCESS;
   iGain = MpCodec_getGain();
   return rc;
}

OsStatus sipXmediaFactoryImpl::getMicrophoneDevice(UtlString& device) const
{
   OsStatus rc = OS_SUCCESS;
   device = DmaTask::getMicDevice();
   return rc;
}

OsStatus sipXmediaFactoryImpl::setVideoPreviewDisplay(void* pDisplay)
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::setVideoQuality(int quality)
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::setVideoParameters(int bitRate, int frameRate)
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoQuality(int& quality) const
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoBitRate(int& bitRate) const
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoFrameRate(int& frameRate) const
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getLocalAudioConnectionId(int& connectionId) const
{
   connectionId = -1;
   return OS_NOT_SUPPORTED;

}

/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

/* //////////////////////////// PRIVATE /////////////////////////////////// */

/* ============================ FUNCTIONS ================================= */
<|endoftext|>


<commit_before>//
// Created by malachi on 12/27/17.
//

#include <catch.hpp>

#include "../coap-dispatcher.h"
#include "../coap-uripath-dispatcher.h"
#include "test-data.h"
#include "test-observer.h"

using namespace moducom::coap;
using namespace moducom::coap::experimental;
using namespace moducom::pipeline;

extern dispatcher_handler_factory_fn test_sub_factories[];

IDispatcherHandler* context_handler_factory(FactoryDispatcherHandlerContext& ctx)
{
    IncomingContext& context = ctx.incoming_context;

#ifdef FEATURE_MCCOAP_INLINE_TOKEN
    return new (ctx.handler_memory.data()) ContextDispatcherHandler(context);
#else
    static moducom::dynamic::PoolBase<moducom::coap::layer2::Token, 8> token_pool;
    return new (ctx.handler_memory.data()) ContextDispatcherHandler(context, token_pool);
#endif
}

IDispatcherHandler* test_factory1(FactoryDispatcherHandlerContext& ctx)
{
    return new (ctx.handler_memory.data()) Buffer16BitDeltaObserver(IsInterestedBase::Never);
}

/*
// Does not work because compiler struggles to cast back down to IMessageObserver
// for some reason
template <const char* uri_path, IMessageObserver* observer>
IDispatcherHandler* uri_helper3(MemoryChunk chunk)
{
    return new (chunk.data()) UriPathDispatcherHandler(uri_path, *observer);
}
*/

template <typename T>
struct array_helper
{
    static CONSTEXPR int count() { return 0; }
};

template <typename T, ptrdiff_t N>
struct array_helper<T[N]>
{
    typedef T element_t;
    static CONSTEXPR ptrdiff_t count() { return N; }
};

/*
template <class TArray>
int _array_helper_count(TArray array)
{
    array_helper<TArray, > array_descriptor;

    return array_helper<TArray>::count();
} */

template <typename T, int size>
CONSTEXPR int _array_helper_count(T (&) [size]) { return size; }

template <typename T, int size>
CONSTEXPR T* _array_helper_contents(T (&t) [size]) { return t; }

/*
template <dispatcher_handler_factory_fn factories[N], int N>
IDispatcherHandler* uri_plus_factory_dispatcher(MemoryChunk chunk)
{

} */

IDispatcherHandler* test_factory2(FactoryDispatcherHandlerContext& ctx)
{
    MemoryChunk& uri_handler_chunk = ctx.handler_memory;
    MemoryChunk v1_handler_chunk = ctx.handler_memory.remainder(sizeof(SingleUriPathObserver));
    MemoryChunk v1_handler_inner_chunk = v1_handler_chunk.remainder(sizeof(FactoryDispatcherHandler));

    FactoryDispatcherHandler* fdh = new (v1_handler_chunk.data()) FactoryDispatcherHandler(
            v1_handler_inner_chunk,
            ctx.incoming_context,
            test_sub_factories, 1);

    // TODO: will need some way to invoke fdh destructor
    return new (uri_handler_chunk.data()) SingleUriPathObserver("v1", *fdh);
}

extern CONSTEXPR char STR_TEST[] = "TEST";

/*
template <typename T, int size>
CONSTEXPR dispatcher_handler_factory_fn uri_helper_helper(T a [size], const char* name)
{
    return &uri_plus_factory_dispatcher<TEST_FACTORY4_NAME, a, size>;
}; */

template <class TArray>
dispatcher_handler_factory_fn uri_helper2(const TArray& array)
{
    typedef array_helper<TArray> array_helper_t;

    int count = _array_helper_count(array);
    const void* contents = _array_helper_contents(array);

    // really needs real constexpr from C++11 to work
    //return &uri_plus_factory_dispatcher<array, count, name>;

    /*
    MemoryChunk& uri_handler_chunk = chunk;
    MemoryChunk sub_handler_chunk = chunk.remainder(sizeof(UriPathDispatcherHandler));
    MemoryChunk sub_handler_inner_chunk = sub_handler_chunk.remainder(sizeof(FactoryDispatcherHandler));

    FactoryDispatcherHandler* fdh = new (sub_handler_chunk.data()) FactoryDispatcherHandler(
            sub_handler_inner_chunk,
            array, count);

    return new (uri_handler_chunk.data()) UriPathDispatcherHandler(uri_path, *fdh); */
};

dispatcher_handler_factory_fn test_factories[] =
{
    context_handler_factory,
    test_factory1,
    test_factory2,
    uri_plus_factory_dispatcher<STR_TEST, test_sub_factories, 1>
};

class TestDispatcherHandler2 : public DispatcherHandlerBase
{
public:
    void on_payload(const MemoryChunk::readonly_t& payload_part,
                    bool last_chunk) OVERRIDE
    {
        REQUIRE(payload_part[0] == 0x10);
        REQUIRE(payload_part[1] == 0x11);
        REQUIRE(payload_part[2] == 0x12);
        REQUIRE(payload_part.length() == 7);
    }
};

extern CONSTEXPR char POS_HANDLER_URI[] = "POS";

extern TestDispatcherHandler2 pos_handler;
TestDispatcherHandler2 pos_handler;

dispatcher_handler_factory_fn test_sub_factories[] =
{
    uri_plus_observer_dispatcher<POS_HANDLER_URI, TestDispatcherHandler2>
};

TEST_CASE("CoAP dispatcher tests", "[coap-dispatcher]")
{
    SECTION("Test 1")
    {
        MemoryChunk chunk(buffer_16bit_delta, sizeof(buffer_16bit_delta));

        Buffer16BitDeltaObserver dispatcherHandler;
        Dispatcher dispatcher;
        //layer3::MemoryChunk<128> chunk;

        dispatcher.head(&dispatcherHandler);
        dispatcher.dispatch(chunk);

        // Dummy test just so we can set a breakpoint here
        REQUIRE(chunk.length() == sizeof(buffer_16bit_delta));
    }
    SECTION("Factory")
    {
        MemoryChunk chunk(buffer_plausible, sizeof(buffer_plausible));

        // in-place new holder
        // FIX: OK all those virtual function tables seem to be bloating
        // our handlers way, way up...
        layer3::MemoryChunk<512> dispatcherBuffer;
        IncomingContext context;

        FactoryDispatcherHandler fdh(dispatcherBuffer, context, test_factories);
        Dispatcher dispatcher;

        // doesn't fully test new UriPath handler because Buffer16BitDeltaObserver
        // is not stateless (and shouldn't be expected to be) but because of that
        // setting it to "Currently" makes it unable to test its own options properly
        dispatcher.head(&fdh);
        dispatcher.dispatch(chunk);
    }
    SECTION("Array experimentation")
    {
        int array[] = { 1, 2, 3 };

        int count = _array_helper_count(array);

        REQUIRE(count == 3);
    }
    SECTION("Size ofs")
    {
        int size1 = sizeof(IMessageObserver);
#ifdef FEATURE_DISCRETE_OBSERVERS
        int size2 = sizeof(IOptionAndPayloadObserver);
        int size3 = sizeof(IOptionObserver);
#endif
        int size4 = sizeof(IDispatcherHandler);
        int size5 = sizeof(IIsInterested);
        int size6 = sizeof(DispatcherHandlerBase);
        int size7 = sizeof(SingleUriPathObserver);
        int size8 = sizeof(FactoryDispatcherHandler);
    }
}
<commit_msg>Begin phasing out old Dispatcher in favor of DecoderSubject<commit_after>//
// Created by malachi on 12/27/17.
//

#include <catch.hpp>

#include "../coap-dispatcher.h"
#include "../coap-uripath-dispatcher.h"
#include "test-data.h"
#include "test-observer.h"

using namespace moducom::coap;
using namespace moducom::coap::experimental;
using namespace moducom::pipeline;

extern dispatcher_handler_factory_fn test_sub_factories[];

IDispatcherHandler* context_handler_factory(FactoryDispatcherHandlerContext& ctx)
{
    IncomingContext& context = ctx.incoming_context;

#ifdef FEATURE_MCCOAP_INLINE_TOKEN
    return new (ctx.handler_memory.data()) ContextDispatcherHandler(context);
#else
    static moducom::dynamic::PoolBase<moducom::coap::layer2::Token, 8> token_pool;
    return new (ctx.handler_memory.data()) ContextDispatcherHandler(context, token_pool);
#endif
}

IDispatcherHandler* test_factory1(FactoryDispatcherHandlerContext& ctx)
{
    return new (ctx.handler_memory.data()) Buffer16BitDeltaObserver(IsInterestedBase::Never);
}

/*
// Does not work because compiler struggles to cast back down to IMessageObserver
// for some reason
template <const char* uri_path, IMessageObserver* observer>
IDispatcherHandler* uri_helper3(MemoryChunk chunk)
{
    return new (chunk.data()) UriPathDispatcherHandler(uri_path, *observer);
}
*/

template <typename T>
struct array_helper
{
    static CONSTEXPR int count() { return 0; }
};

template <typename T, ptrdiff_t N>
struct array_helper<T[N]>
{
    typedef T element_t;
    static CONSTEXPR ptrdiff_t count() { return N; }
};

/*
template <class TArray>
int _array_helper_count(TArray array)
{
    array_helper<TArray, > array_descriptor;

    return array_helper<TArray>::count();
} */

template <typename T, int size>
CONSTEXPR int _array_helper_count(T (&) [size]) { return size; }

template <typename T, int size>
CONSTEXPR T* _array_helper_contents(T (&t) [size]) { return t; }

/*
template <dispatcher_handler_factory_fn factories[N], int N>
IDispatcherHandler* uri_plus_factory_dispatcher(MemoryChunk chunk)
{

} */

IDispatcherHandler* test_factory2(FactoryDispatcherHandlerContext& ctx)
{
    MemoryChunk& uri_handler_chunk = ctx.handler_memory;
    MemoryChunk v1_handler_chunk = ctx.handler_memory.remainder(sizeof(SingleUriPathObserver));
    MemoryChunk v1_handler_inner_chunk = v1_handler_chunk.remainder(sizeof(FactoryDispatcherHandler));

    FactoryDispatcherHandler* fdh = new (v1_handler_chunk.data()) FactoryDispatcherHandler(
            v1_handler_inner_chunk,
            ctx.incoming_context,
            test_sub_factories, 1);

    // TODO: will need some way to invoke fdh destructor
    return new (uri_handler_chunk.data()) SingleUriPathObserver("v1", *fdh);
}

extern CONSTEXPR char STR_TEST[] = "TEST";

/*
template <typename T, int size>
CONSTEXPR dispatcher_handler_factory_fn uri_helper_helper(T a [size], const char* name)
{
    return &uri_plus_factory_dispatcher<TEST_FACTORY4_NAME, a, size>;
}; */

template <class TArray>
dispatcher_handler_factory_fn uri_helper2(const TArray& array)
{
    typedef array_helper<TArray> array_helper_t;

    int count = _array_helper_count(array);
    const void* contents = _array_helper_contents(array);

    // really needs real constexpr from C++11 to work
    //return &uri_plus_factory_dispatcher<array, count, name>;

    /*
    MemoryChunk& uri_handler_chunk = chunk;
    MemoryChunk sub_handler_chunk = chunk.remainder(sizeof(UriPathDispatcherHandler));
    MemoryChunk sub_handler_inner_chunk = sub_handler_chunk.remainder(sizeof(FactoryDispatcherHandler));

    FactoryDispatcherHandler* fdh = new (sub_handler_chunk.data()) FactoryDispatcherHandler(
            sub_handler_inner_chunk,
            array, count);

    return new (uri_handler_chunk.data()) UriPathDispatcherHandler(uri_path, *fdh); */
};

dispatcher_handler_factory_fn test_factories[] =
{
    context_handler_factory,
    test_factory1,
    test_factory2,
    uri_plus_factory_dispatcher<STR_TEST, test_sub_factories, 1>
};

class TestDispatcherHandler2 : public DispatcherHandlerBase
{
public:
    void on_payload(const MemoryChunk::readonly_t& payload_part,
                    bool last_chunk) OVERRIDE
    {
        REQUIRE(payload_part[0] == 0x10);
        REQUIRE(payload_part[1] == 0x11);
        REQUIRE(payload_part[2] == 0x12);
        REQUIRE(payload_part.length() == 7);
    }
};

extern CONSTEXPR char POS_HANDLER_URI[] = "POS";

extern TestDispatcherHandler2 pos_handler;
TestDispatcherHandler2 pos_handler;

dispatcher_handler_factory_fn test_sub_factories[] =
{
    uri_plus_observer_dispatcher<POS_HANDLER_URI, TestDispatcherHandler2>
};

TEST_CASE("CoAP dispatcher tests", "[coap-dispatcher]")
{
    SECTION("Factory")
    {
        MemoryChunk chunk(buffer_plausible, sizeof(buffer_plausible));

        // in-place new holder
        // FIX: OK all those virtual function tables seem to be bloating
        // our handlers way, way up...
        layer3::MemoryChunk<512> dispatcherBuffer;
        IncomingContext context;

        FactoryDispatcherHandler fdh(dispatcherBuffer, context, test_factories);
        Dispatcher dispatcher;

        // doesn't fully test new UriPath handler because Buffer16BitDeltaObserver
        // is not stateless (and shouldn't be expected to be) but because of that
        // setting it to "Currently" makes it unable to test its own options properly
        dispatcher.head(&fdh);
        dispatcher.dispatch(chunk);
    }
    SECTION("Array experimentation")
    {
        int array[] = { 1, 2, 3 };

        int count = _array_helper_count(array);

        REQUIRE(count == 3);
    }
    SECTION("Size ofs")
    {
        int size1 = sizeof(IMessageObserver);
#ifdef FEATURE_DISCRETE_OBSERVERS
        int size2 = sizeof(IOptionAndPayloadObserver);
        int size3 = sizeof(IOptionObserver);
#endif
        int size4 = sizeof(IDispatcherHandler);
        int size5 = sizeof(IIsInterested);
        int size6 = sizeof(DispatcherHandlerBase);
        int size7 = sizeof(SingleUriPathObserver);
        int size8 = sizeof(FactoryDispatcherHandler);
    }
}
<|endoftext|>