<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/chromeos/status/language_menu_button.h"

#include <string>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/time.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

// The language menu consists of 3 parts (in this order):
//
//   (1) XKB layout names and IME languages names. The size of the list is
//       always >= 1.
//   (2) IME properties. This list might be empty.
//   (3) "Configure IME..." button.
//
// Example of the menu (Japanese):
//
// ============================== (border of the popup window)
// [ ] US                         (|index| in the following functions is 0)
// [*] Anthy
// [ ] PinYin
// ------------------------------ (separator)
// [*] Hiragana                   (index = 5, The property has 2 radio groups)
// [ ] Katakana
// [ ] HalfWidthKatakana
// [*] Roman
// [ ] Kana
// ------------------------------ (separator)
// Configure IME...               (index = 11)
// ============================== (border of the popup window)
//
// Example of the menu (Simplified Chinese):
//
// ============================== (border of the popup window)
// [ ] US
// [ ] Anthy
// [*] PinYin
// ------------------------------ (separator)
// Switch to full letter mode     (The property has 2 command buttons)
// Switch to half punctuation mode
// ------------------------------ (separator)
// Configure IME...
// ============================== (border of the popup window)
//

namespace {

// Constants to specify the type of items in |model_|.
enum {
  COMMAND_ID_LANGUAGES = 0,  // US, Anthy, PinYin, ...
  COMMAND_ID_IME_PROPERTIES,  // Hiragana, Katakana, ...
  COMMAND_ID_CONFIGURE_IME,  // The "Configure IME..." button.
};

// A group ID for IME properties starts from 0. We use the huge value for the
// XKB/IME language list to avoid conflict.
const int kRadioGroupLanguage = 1 << 16;
const int kRadioGroupNone = -1;
const size_t kMaxLanguageNameLen = 7;
const wchar_t kSpacer[] = L"MMMMMMM";

// Converts chromeos::InputLanguage object into human readable string. Returns
// a string for the drop-down menu if |for_menu| is true. Otherwise, returns a
// string for the status area.
std::string FormatInputLanguage(
    const chromeos::InputLanguage& language, bool for_menu) {
  std::string formatted = language.display_name;
  if (formatted.empty()) {
    formatted = language.id;
  }
  if (for_menu) {
    switch (language.category) {
      case chromeos::LANGUAGE_CATEGORY_XKB:
        // TODO(yusukes): Use message catalog.
        formatted += " (Layout)";
        break;
      case chromeos::LANGUAGE_CATEGORY_IME:
        // TODO(yusukes): Use message catalog.
        formatted += " (IME)";
        break;
    }
  } else {
    // For status area. Trim the string.
    formatted = formatted.substr(0, kMaxLanguageNameLen);
    // TODO(yusukes): Simple substr() does not work for non-ASCII string.
    // TODO(yusukes): How can we ensure that the trimmed string does not
    // overflow the area?
  }
  return formatted;
}

}  // namespace

namespace chromeos {

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton

LanguageMenuButton::LanguageMenuButton(StatusAreaHost* host)
    : MenuButton(NULL, std::wstring(), this, false),
      language_list_(LanguageLibrary::Get()->GetActiveLanguages()),
      model_(NULL),
      // Be aware that the constructor of |language_menu_| calls GetItemCount()
      // in this class. Therefore, GetItemCount() have to return 0 when
      // |model_| is NULL.
      ALLOW_THIS_IN_INITIALIZER_LIST(language_menu_(this)),
      host_(host) {
  DCHECK(language_list_.get() && !language_list_->empty());
  // Update the model
  RebuildModel();
  // Grab the real estate.
  UpdateIcon(kSpacer);
  // Display the default XKB name (usually "US").
  const std::string name = FormatInputLanguage(language_list_->at(0), false);
  UpdateIcon(UTF8ToWide(name));
  LanguageLibrary::Get()->AddObserver(this);
}

LanguageMenuButton::~LanguageMenuButton() {
  LanguageLibrary::Get()->RemoveObserver(this);
}

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton, menus::MenuModel implementation:

int LanguageMenuButton::GetCommandIdAt(int index) const {
  return 0;  // dummy
}

bool LanguageMenuButton::IsLabelDynamicAt(int index) const {
  // Menu content for the language button could change time by time.
  return true;
}

bool LanguageMenuButton::GetAcceleratorAt(
    int index, menus::Accelerator* accelerator) const {
  // Views for Chromium OS does not support accelerators yet.
  return false;
}

bool LanguageMenuButton::IsItemCheckedAt(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(language_list_.get());

  if (IndexIsInLanguageList(index)) {
    const InputLanguage& language = language_list_->at(index);
    return language == LanguageLibrary::Get()->current_language();
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = LanguageLibrary::Get()->current_ime_properties();
    return property_list.at(index).is_selection_item_checked;
  }

  // Separator(s) or the "Configure IME" button.
  return false;
}

int LanguageMenuButton::GetGroupIdAt(int index) const {
  DCHECK_GE(index, 0);

  if (IndexIsInLanguageList(index)) {
    return kRadioGroupLanguage;
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = LanguageLibrary::Get()->current_ime_properties();
    return property_list.at(index).selection_item_id;
  }

  return kRadioGroupNone;
}

bool LanguageMenuButton::HasIcons() const  {
  // TODO(yusukes): Display IME icons.
  return false;
}

bool LanguageMenuButton::GetIconAt(int index, SkBitmap* icon) const {
  // TODO(yusukes): Display IME icons.
  return false;
}

bool LanguageMenuButton::IsEnabledAt(int index) const {
  // Just return true so all IMEs, XKB layouts, and IME properties could be
  // clicked.
  return true;
}

menus::MenuModel* LanguageMenuButton::GetSubmenuModelAt(int index) const {
  // We don't use nested menus.
  return NULL;
}

void LanguageMenuButton::HighlightChangedTo(int index) {
  // Views for Chromium OS does not support this interface yet.
}

void LanguageMenuButton::MenuWillShow() {
  // Views for Chromium OS does not support this interface yet.
}

int LanguageMenuButton::GetItemCount() const {
  if (!model_.get()) {
    // Model is not constructed yet. This means that LanguageMenuButton is
    // being constructed. Return zero.
    return 0;
  }
  return model_->GetItemCount();
}

menus::MenuModel::ItemType LanguageMenuButton::GetTypeAt(int index) const {
  DCHECK_GE(index, 0);

  if (IndexPointsToConfigureImeMenuItem(index)) {
    return menus::MenuModel::TYPE_COMMAND;  // "Configure IME"
  }

  if (IndexIsInLanguageList(index)) {
    return menus::MenuModel::TYPE_RADIO;
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = LanguageLibrary::Get()->current_ime_properties();
    if (property_list.at(index).is_selection_item) {
      return menus::MenuModel::TYPE_RADIO;
    }
    return menus::MenuModel::TYPE_COMMAND;
  }

  return menus::MenuModel::TYPE_SEPARATOR;
}

string16 LanguageMenuButton::GetLabelAt(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(language_list_.get());

  if (IndexPointsToConfigureImeMenuItem(index)) {
    // TODO(yusukes): Use message catalog.
    return WideToUTF16(L"Configure IME...");
  }

  std::string name;
  if (IndexIsInLanguageList(index)) {
    name = FormatInputLanguage(language_list_->at(index), true);
  } else if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = LanguageLibrary::Get()->current_ime_properties();
    name = property_list.at(index).label;
  }

  return UTF8ToUTF16(name);
}

void LanguageMenuButton::ActivatedAt(int index) {
  DCHECK_GE(index, 0);
  DCHECK(language_list_.get());

  if (IndexPointsToConfigureImeMenuItem(index)) {
    host_->OpenButtonOptions(this);
    return;
  }

  if (IndexIsInLanguageList(index)) {
    // Inter-IME switching or IME-XKB switching.
    const InputLanguage& language = language_list_->at(index);
    LanguageLibrary::Get()->ChangeLanguage(language.category, language.id);
    return;
  }

  if (GetPropertyIndex(index, &index)) {
    // Intra-IME switching (e.g. Japanese-Hiragana to Japanese-Katakana).
    const ImePropertyList& property_list
        = LanguageLibrary::Get()->current_ime_properties();
    const std::string key = property_list.at(index).key;
    if (property_list.at(index).is_selection_item) {
      // Radio button is clicked.
      const int id = property_list.at(index).selection_item_id;
      // First, deactivate all other properties in the same radio group.
      for (int i = 0; i < static_cast<int>(property_list.size()); ++i) {
        if (i != index && id == property_list.at(i).selection_item_id) {
          LanguageLibrary::Get()->DeactivateImeProperty(
              property_list.at(i).key);
        }
      }
      // Then, activate the property clicked.
      LanguageLibrary::Get()->ActivateImeProperty(key);
    } else {
      // Command button like "Switch to half punctuation mode" is clicked.
      // We can always use "Deactivate" for command buttons.
      LanguageLibrary::Get()->DeactivateImeProperty(key);
    }
    return;
  }

  // Separators are not clickable.
  NOTREACHED();
}

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton, views::ViewMenuDelegate implementation:

void LanguageMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
  language_list_.reset(LanguageLibrary::Get()->GetActiveLanguages());
  RebuildModel();
  language_menu_.Rebuild();
  language_menu_.UpdateStates();
  language_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
}

////////////////////////////////////////////////////////////////////////////////
// LanguageLibrary::Observer implementation:

void LanguageMenuButton::LanguageChanged(LanguageLibrary* obj) {
  const std::string name = FormatInputLanguage(obj->current_language(), false);
  UpdateIcon(UTF8ToWide(name));
}

void LanguageMenuButton::ImePropertiesChanged(LanguageLibrary* obj) {
  RebuildModel();
}

void LanguageMenuButton::UpdateIcon(const std::wstring& name) {
  set_border(NULL);
  SetFont(ResourceBundle::GetSharedInstance().GetFont(
      ResourceBundle::BaseFont).DeriveFont(0, gfx::Font::BOLD));
  SetEnabledColor(SK_ColorWHITE);
  SetShowHighlighted(false);
  SetText(name);
  // TODO(yusukes): Show icon on the status area?
  set_alignment(TextButton::ALIGN_RIGHT);
  SchedulePaint();
}

void LanguageMenuButton::RebuildModel() {
  model_.reset(new menus::SimpleMenuModel(NULL));
  string16 dummy_label = UTF8ToUTF16("");
  // Indicates if separator's needed before each section.
  bool need_separator = false;

  if (!language_list_->empty()) {
    // We "abuse" the command_id and group_id arguments of AddRadioItem method.
    // A COMMAND_ID_XXX enum value is passed as command_id, and array index of
    // |language_list_| or |property_list| is passed as group_id.
    for (size_t i = 0; i < language_list_->size(); ++i) {
      model_->AddRadioItem(COMMAND_ID_LANGUAGES, dummy_label, i);
    }
    need_separator = true;
  }

  const ImePropertyList& property_list
      = LanguageLibrary::Get()->current_ime_properties();
  if (!property_list.empty()) {
    if (need_separator)
      model_->AddSeparator();
    for (size_t i = 0; i < property_list.size(); ++i) {
      model_->AddRadioItem(COMMAND_ID_IME_PROPERTIES, dummy_label, i);
    }
    need_separator = true;
  }

  if (host_->ShouldOpenButtonOptions(this)) {
    // Note: We use AddSeparator() for separators, and AddRadioItem() for all
    // other items even if an item is not actually a radio item.
    if (need_separator)
      model_->AddSeparator();
    model_->AddRadioItem(COMMAND_ID_CONFIGURE_IME, dummy_label, 0 /* dummy */);
  }
}

bool LanguageMenuButton::IndexIsInLanguageList(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(model_.get());

  return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
          (model_->GetCommandIdAt(index) == COMMAND_ID_LANGUAGES));
}

bool LanguageMenuButton::GetPropertyIndex(
    int index, int* property_index) const {
  DCHECK_GE(index, 0);
  DCHECK(property_index);
  DCHECK(model_.get());

  if ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
      (model_->GetCommandIdAt(index) == COMMAND_ID_IME_PROPERTIES)) {
    *property_index = model_->GetGroupIdAt(index);
    return true;
  }
  return false;
}

bool LanguageMenuButton::IndexPointsToConfigureImeMenuItem(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(model_.get());

  return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
          (model_->GetCommandIdAt(index) == COMMAND_ID_CONFIGURE_IME));
}

// TODO(yusukes): Register and handle hotkeys for IME and XKB switching?

}  // namespace chromeos
<commit_msg>Remove obsolete TODOs. No code change.<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/chromeos/status/language_menu_button.h"

#include <string>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/time.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

// The language menu consists of 3 parts (in this order):
//
//   (1) XKB layout names and IME languages names. The size of the list is
//       always >= 1.
//   (2) IME properties. This list might be empty.
//   (3) "Configure IME..." button.
//
// Example of the menu (Japanese):
//
// ============================== (border of the popup window)
// [ ] US                         (|index| in the following functions is 0)
// [*] Anthy
// [ ] PinYin
// ------------------------------ (separator)
// [*] Hiragana                   (index = 5, The property has 2 radio groups)
// [ ] Katakana
// [ ] HalfWidthKatakana
// [*] Roman
// [ ] Kana
// ------------------------------ (separator)
// Configure IME...               (index = 11)
// ============================== (border of the popup window)
//
// Example of the menu (Simplified Chinese):
//
// ============================== (border of the popup window)
// [ ] US
// [ ] Anthy
// [*] PinYin
// ------------------------------ (separator)
// Switch to full letter mode     (The property has 2 command buttons)
// Switch to half punctuation mode
// ------------------------------ (separator)
// Configure IME...
// ============================== (border of the popup window)
//

namespace {

// Constants to specify the type of items in |model_|.
enum {
  COMMAND_ID_LANGUAGES = 0,  // US, Anthy, PinYin, ...
  COMMAND_ID_IME_PROPERTIES,  // Hiragana, Katakana, ...
  COMMAND_ID_CONFIGURE_IME,  // The "Configure IME..." button.
};

// A group ID for IME properties starts from 0. We use the huge value for the
// XKB/IME language list to avoid conflict.
const int kRadioGroupLanguage = 1 << 16;
const int kRadioGroupNone = -1;
const size_t kMaxLanguageNameLen = 7;
const wchar_t kSpacer[] = L"MMMMMMM";

// Converts chromeos::InputLanguage object into human readable string. Returns
// a string for the drop-down menu if |for_menu| is true. Otherwise, returns a
// string for the status area.
std::string FormatInputLanguage(
    const chromeos::InputLanguage& language, bool for_menu) {
  std::string formatted = language.display_name;
  if (formatted.empty()) {
    formatted = language.id;
  }
  if (for_menu) {
    switch (language.category) {
      case chromeos::LANGUAGE_CATEGORY_XKB:
        // TODO(yusukes): Use message catalog.
        formatted += " (Layout)";
        break;
      case chromeos::LANGUAGE_CATEGORY_IME:
        // TODO(yusukes): Use message catalog.
        formatted += " (IME)";
        break;
    }
  } else {
    // For status area. Trim the string.
    formatted = formatted.substr(0, kMaxLanguageNameLen);
    // TODO(yusukes): Simple substr() does not work for non-ASCII string.
    // TODO(yusukes): How can we ensure that the trimmed string does not
    // overflow the area?
  }
  return formatted;
}

}  // namespace

namespace chromeos {

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton

LanguageMenuButton::LanguageMenuButton(StatusAreaHost* host)
    : MenuButton(NULL, std::wstring(), this, false),
      language_list_(LanguageLibrary::Get()->GetActiveLanguages()),
      model_(NULL),
      // Be aware that the constructor of |language_menu_| calls GetItemCount()
      // in this class. Therefore, GetItemCount() have to return 0 when
      // |model_| is NULL.
      ALLOW_THIS_IN_INITIALIZER_LIST(language_menu_(this)),
      host_(host) {
  DCHECK(language_list_.get() && !language_list_->empty());
  // Update the model
  RebuildModel();
  // Grab the real estate.
  UpdateIcon(kSpacer);
  // Display the default XKB name (usually "US").
  const std::string name = FormatInputLanguage(language_list_->at(0), false);
  UpdateIcon(UTF8ToWide(name));
  LanguageLibrary::Get()->AddObserver(this);
}

LanguageMenuButton::~LanguageMenuButton() {
  LanguageLibrary::Get()->RemoveObserver(this);
}

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton, menus::MenuModel implementation:

int LanguageMenuButton::GetCommandIdAt(int index) const {
  return 0;  // dummy
}

bool LanguageMenuButton::IsLabelDynamicAt(int index) const {
  // Menu content for the language button could change time by time.
  return true;
}

bool LanguageMenuButton::GetAcceleratorAt(
    int index, menus::Accelerator* accelerator) const {
  // Views for Chromium OS does not support accelerators yet.
  return false;
}

bool LanguageMenuButton::IsItemCheckedAt(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(language_list_.get());

  if (IndexIsInLanguageList(index)) {
    const InputLanguage& language = language_list_->at(index);
    return language == LanguageLibrary::Get()->current_language();
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = LanguageLibrary::Get()->current_ime_properties();
    return property_list.at(index).is_selection_item_checked;
  }

  // Separator(s) or the "Configure IME" button.
  return false;
}

int LanguageMenuButton::GetGroupIdAt(int index) const {
  DCHECK_GE(index, 0);

  if (IndexIsInLanguageList(index)) {
    return kRadioGroupLanguage;
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = LanguageLibrary::Get()->current_ime_properties();
    return property_list.at(index).selection_item_id;
  }

  return kRadioGroupNone;
}

bool LanguageMenuButton::HasIcons() const  {
  // We don't support IME nor keyboard icons on Chrome OS.
  return false;
}

bool LanguageMenuButton::GetIconAt(int index, SkBitmap* icon) const {
  return false;
}

bool LanguageMenuButton::IsEnabledAt(int index) const {
  // Just return true so all IMEs, XKB layouts, and IME properties could be
  // clicked.
  return true;
}

menus::MenuModel* LanguageMenuButton::GetSubmenuModelAt(int index) const {
  // We don't use nested menus.
  return NULL;
}

void LanguageMenuButton::HighlightChangedTo(int index) {
  // Views for Chromium OS does not support this interface yet.
}

void LanguageMenuButton::MenuWillShow() {
  // Views for Chromium OS does not support this interface yet.
}

int LanguageMenuButton::GetItemCount() const {
  if (!model_.get()) {
    // Model is not constructed yet. This means that LanguageMenuButton is
    // being constructed. Return zero.
    return 0;
  }
  return model_->GetItemCount();
}

menus::MenuModel::ItemType LanguageMenuButton::GetTypeAt(int index) const {
  DCHECK_GE(index, 0);

  if (IndexPointsToConfigureImeMenuItem(index)) {
    return menus::MenuModel::TYPE_COMMAND;  // "Configure IME"
  }

  if (IndexIsInLanguageList(index)) {
    return menus::MenuModel::TYPE_RADIO;
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = LanguageLibrary::Get()->current_ime_properties();
    if (property_list.at(index).is_selection_item) {
      return menus::MenuModel::TYPE_RADIO;
    }
    return menus::MenuModel::TYPE_COMMAND;
  }

  return menus::MenuModel::TYPE_SEPARATOR;
}

string16 LanguageMenuButton::GetLabelAt(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(language_list_.get());

  if (IndexPointsToConfigureImeMenuItem(index)) {
    // TODO(yusukes): Use message catalog.
    return WideToUTF16(L"Configure IME...");
  }

  std::string name;
  if (IndexIsInLanguageList(index)) {
    name = FormatInputLanguage(language_list_->at(index), true);
  } else if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = LanguageLibrary::Get()->current_ime_properties();
    name = property_list.at(index).label;
  }

  return UTF8ToUTF16(name);
}

void LanguageMenuButton::ActivatedAt(int index) {
  DCHECK_GE(index, 0);
  DCHECK(language_list_.get());

  if (IndexPointsToConfigureImeMenuItem(index)) {
    host_->OpenButtonOptions(this);
    return;
  }

  if (IndexIsInLanguageList(index)) {
    // Inter-IME switching or IME-XKB switching.
    const InputLanguage& language = language_list_->at(index);
    LanguageLibrary::Get()->ChangeLanguage(language.category, language.id);
    return;
  }

  if (GetPropertyIndex(index, &index)) {
    // Intra-IME switching (e.g. Japanese-Hiragana to Japanese-Katakana).
    const ImePropertyList& property_list
        = LanguageLibrary::Get()->current_ime_properties();
    const std::string key = property_list.at(index).key;
    if (property_list.at(index).is_selection_item) {
      // Radio button is clicked.
      const int id = property_list.at(index).selection_item_id;
      // First, deactivate all other properties in the same radio group.
      for (int i = 0; i < static_cast<int>(property_list.size()); ++i) {
        if (i != index && id == property_list.at(i).selection_item_id) {
          LanguageLibrary::Get()->DeactivateImeProperty(
              property_list.at(i).key);
        }
      }
      // Then, activate the property clicked.
      LanguageLibrary::Get()->ActivateImeProperty(key);
    } else {
      // Command button like "Switch to half punctuation mode" is clicked.
      // We can always use "Deactivate" for command buttons.
      LanguageLibrary::Get()->DeactivateImeProperty(key);
    }
    return;
  }

  // Separators are not clickable.
  NOTREACHED();
}

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton, views::ViewMenuDelegate implementation:

void LanguageMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
  language_list_.reset(LanguageLibrary::Get()->GetActiveLanguages());
  RebuildModel();
  language_menu_.Rebuild();
  language_menu_.UpdateStates();
  language_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
}

////////////////////////////////////////////////////////////////////////////////
// LanguageLibrary::Observer implementation:

void LanguageMenuButton::LanguageChanged(LanguageLibrary* obj) {
  const std::string name = FormatInputLanguage(obj->current_language(), false);
  UpdateIcon(UTF8ToWide(name));
}

void LanguageMenuButton::ImePropertiesChanged(LanguageLibrary* obj) {
  RebuildModel();
}

void LanguageMenuButton::UpdateIcon(const std::wstring& name) {
  set_border(NULL);
  SetFont(ResourceBundle::GetSharedInstance().GetFont(
      ResourceBundle::BaseFont).DeriveFont(0, gfx::Font::BOLD));
  SetEnabledColor(SK_ColorWHITE);
  SetShowHighlighted(false);
  SetText(name);
  set_alignment(TextButton::ALIGN_RIGHT);
  SchedulePaint();
}

void LanguageMenuButton::RebuildModel() {
  model_.reset(new menus::SimpleMenuModel(NULL));
  string16 dummy_label = UTF8ToUTF16("");
  // Indicates if separator's needed before each section.
  bool need_separator = false;

  if (!language_list_->empty()) {
    // We "abuse" the command_id and group_id arguments of AddRadioItem method.
    // A COMMAND_ID_XXX enum value is passed as command_id, and array index of
    // |language_list_| or |property_list| is passed as group_id.
    for (size_t i = 0; i < language_list_->size(); ++i) {
      model_->AddRadioItem(COMMAND_ID_LANGUAGES, dummy_label, i);
    }
    need_separator = true;
  }

  const ImePropertyList& property_list
      = LanguageLibrary::Get()->current_ime_properties();
  if (!property_list.empty()) {
    if (need_separator)
      model_->AddSeparator();
    for (size_t i = 0; i < property_list.size(); ++i) {
      model_->AddRadioItem(COMMAND_ID_IME_PROPERTIES, dummy_label, i);
    }
    need_separator = true;
  }

  if (host_->ShouldOpenButtonOptions(this)) {
    // Note: We use AddSeparator() for separators, and AddRadioItem() for all
    // other items even if an item is not actually a radio item.
    if (need_separator)
      model_->AddSeparator();
    model_->AddRadioItem(COMMAND_ID_CONFIGURE_IME, dummy_label, 0 /* dummy */);
  }
}

bool LanguageMenuButton::IndexIsInLanguageList(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(model_.get());

  return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
          (model_->GetCommandIdAt(index) == COMMAND_ID_LANGUAGES));
}

bool LanguageMenuButton::GetPropertyIndex(
    int index, int* property_index) const {
  DCHECK_GE(index, 0);
  DCHECK(property_index);
  DCHECK(model_.get());

  if ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
      (model_->GetCommandIdAt(index) == COMMAND_ID_IME_PROPERTIES)) {
    *property_index = model_->GetGroupIdAt(index);
    return true;
  }
  return false;
}

bool LanguageMenuButton::IndexPointsToConfigureImeMenuItem(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(model_.get());

  return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
          (model_->GetCommandIdAt(index) == COMMAND_ID_CONFIGURE_IME));
}

// TODO(yusukes): Register and handle hotkeys for IME and XKB switching?

}  // namespace chromeos
<|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/browser.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/test/ui_test_utils.h"

namespace {

class MockInstallUI : public ExtensionInstallUI {
 public:
  explicit MockInstallUI(Profile* profile) :
      ExtensionInstallUI(profile), confirmation_requested_(false) {}

  // Did the Delegate request confirmation?
  bool confirmation_requested() { return confirmation_requested_; }

  // Overriding some of the ExtensionInstallUI API.
  void ConfirmInstall(Delegate* delegate, const Extension* extension) {
    confirmation_requested_ = true;
    delegate->InstallUIProceed();
  }
  void OnInstallSuccess(const Extension* extension) {
    MessageLoopForUI::current()->Quit();
  }
  void OnInstallFailure(const std::string& error) {
    ADD_FAILURE() << "insall failed";
    MessageLoopForUI::current()->Quit();
  }

 private:
  bool confirmation_requested_;
};

}  // namespace

class ExtensionCrxInstallerTest : public ExtensionBrowserTest {
 public:
  // Installs a crx from |crx_relpath| (a path relative to the extension test
  // data dir) with expected id |id|. Returns whether a confirmation prompt
  // happened or not.
  bool DidWhitelistInstallPrompt(const std::string& crx_relpath,
                                 const std::string& id) {
    ExtensionsService* service = browser()->profile()->GetExtensionsService();
    MockInstallUI* mock_install_ui = new MockInstallUI(browser()->profile());

    scoped_refptr<CrxInstaller> installer(
        new CrxInstaller(service->install_directory(),
                         service,
                         mock_install_ui /* ownership transferred */));

    installer->set_allow_silent_install(true);
    CrxInstaller::SetWhitelistedInstallId(id);

    FilePath crx_path = test_data_dir_.AppendASCII(crx_relpath);
    installer->InstallCrx(crx_path);
    ui_test_utils::RunMessageLoop();

    return mock_install_ui->confirmation_requested();
  }
};

IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, Whitelisting) {
  // A regular extension should give no prompt.
  EXPECT_FALSE(DidWhitelistInstallPrompt("good.crx",
                                         "ldnnhddmnhbkjipkidpdiheffobcpfmf"));

  // An extension with NPAPI should give a prompt.
  EXPECT_TRUE(DidWhitelistInstallPrompt("uitest/plugins.crx",
                                        "hdgllgikmikobbofgnabhfimcfoopgnd"));
}
<commit_msg>Don't run test with NPAPI extension on ChromeOS<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/browser.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/test/ui_test_utils.h"

namespace {

class MockInstallUI : public ExtensionInstallUI {
 public:
  explicit MockInstallUI(Profile* profile) :
      ExtensionInstallUI(profile), confirmation_requested_(false) {}

  // Did the Delegate request confirmation?
  bool confirmation_requested() { return confirmation_requested_; }

  // Overriding some of the ExtensionInstallUI API.
  void ConfirmInstall(Delegate* delegate, const Extension* extension) {
    confirmation_requested_ = true;
    delegate->InstallUIProceed();
  }
  void OnInstallSuccess(const Extension* extension) {
    MessageLoopForUI::current()->Quit();
  }
  void OnInstallFailure(const std::string& error) {
    ADD_FAILURE() << "insall failed";
    MessageLoopForUI::current()->Quit();
  }

 private:
  bool confirmation_requested_;
};

}  // namespace

class ExtensionCrxInstallerTest : public ExtensionBrowserTest {
 public:
  // Installs a crx from |crx_relpath| (a path relative to the extension test
  // data dir) with expected id |id|. Returns whether a confirmation prompt
  // happened or not.
  bool DidWhitelistInstallPrompt(const std::string& crx_relpath,
                                 const std::string& id) {
    ExtensionsService* service = browser()->profile()->GetExtensionsService();
    MockInstallUI* mock_install_ui = new MockInstallUI(browser()->profile());

    scoped_refptr<CrxInstaller> installer(
        new CrxInstaller(service->install_directory(),
                         service,
                         mock_install_ui /* ownership transferred */));

    installer->set_allow_silent_install(true);
    CrxInstaller::SetWhitelistedInstallId(id);

    FilePath crx_path = test_data_dir_.AppendASCII(crx_relpath);
    installer->InstallCrx(crx_path);
    ui_test_utils::RunMessageLoop();

    return mock_install_ui->confirmation_requested();
  }
};

IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, Whitelisting) {
  // A regular extension should give no prompt.
  EXPECT_FALSE(DidWhitelistInstallPrompt("good.crx",
                                         "ldnnhddmnhbkjipkidpdiheffobcpfmf"));
#if !defined(OS_CHROMEOS)
  // An extension with NPAPI should give a prompt.
  EXPECT_TRUE(DidWhitelistInstallPrompt("uitest/plugins.crx",
                                        "hdgllgikmikobbofgnabhfimcfoopgnd"));
#endif // !defined(OS_CHROMEOS
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_apitest.h"

IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Storage) {
  ASSERT_TRUE(RunExtensionTest("storage")) << message_;
}
<commit_msg>Disable test failing since r29947. <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/extensions/extension_apitest.h"

// Started failing with r29947. WebKit merge 49961:49992.
IN_PROC_BROWSER_TEST_F(DISABLED_ExtensionApiTest, Storage) {
  ASSERT_TRUE(RunExtensionTest("storage")) << message_;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bench/bench.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
#include <test/util/mining.h>
#include <test/util/setup_common.h>
#include <test/util/wallet.h>
#include <txmempool.h>
#include <validation.h>

#include <vector>

static void AssembleBlock(benchmark::Bench& bench)
{
    const auto test_setup = MakeNoLogFileContext<const TestingSetup>();

    const std::vector<unsigned char> op_true{OP_TRUE};
    CScriptWitness witness;
    witness.stack.push_back(op_true);

    uint256 witness_program;
    CSHA256().Write(&op_true[0], op_true.size()).Finalize(witness_program.begin());

    const CScript SCRIPT_PUB{CScript(OP_0) << std::vector<unsigned char>{witness_program.begin(), witness_program.end()}};

    // Collect some loose transactions that spend the coinbases of our mined blocks
    constexpr size_t NUM_BLOCKS{200};
    std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY + 1> txs;
    for (size_t b{0}; b < NUM_BLOCKS; ++b) {
        CMutableTransaction tx;
        tx.vin.push_back(MineBlock(test_setup->m_node, SCRIPT_PUB));
        tx.vin.back().scriptWitness = witness;
        tx.vout.emplace_back(1337, SCRIPT_PUB);
        if (NUM_BLOCKS - b >= COINBASE_MATURITY)
            txs.at(b) = MakeTransactionRef(tx);
    }
    {
        LOCK(::cs_main); // Required for ::AcceptToMemoryPool.

        for (const auto& txr : txs) {
            const MempoolAcceptResult res = ::AcceptToMemoryPool(::ChainstateActive(), *test_setup->m_node.mempool, txr, false /* bypass_limits */);
            assert(res.m_result_type == MempoolAcceptResult::ResultType::VALID);
        }
    }

    bench.run([&] {
        PrepareBlock(test_setup->m_node, SCRIPT_PUB);
    });
}

BENCHMARK(AssembleBlock);
<commit_msg>bench: Remove duplicate constants<commit_after>// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bench/bench.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
#include <test/util/mining.h>
#include <test/util/script.h>
#include <test/util/setup_common.h>
#include <test/util/wallet.h>
#include <txmempool.h>
#include <validation.h>

#include <vector>

static void AssembleBlock(benchmark::Bench& bench)
{
    const auto test_setup = MakeNoLogFileContext<const TestingSetup>();

    CScriptWitness witness;
    witness.stack.push_back(WITNESS_STACK_ELEM_OP_TRUE);

    // Collect some loose transactions that spend the coinbases of our mined blocks
    constexpr size_t NUM_BLOCKS{200};
    std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY + 1> txs;
    for (size_t b{0}; b < NUM_BLOCKS; ++b) {
        CMutableTransaction tx;
        tx.vin.push_back(MineBlock(test_setup->m_node, P2WSH_OP_TRUE));
        tx.vin.back().scriptWitness = witness;
        tx.vout.emplace_back(1337, P2WSH_OP_TRUE);
        if (NUM_BLOCKS - b >= COINBASE_MATURITY)
            txs.at(b) = MakeTransactionRef(tx);
    }
    {
        LOCK(::cs_main); // Required for ::AcceptToMemoryPool.

        for (const auto& txr : txs) {
            const MempoolAcceptResult res = ::AcceptToMemoryPool(::ChainstateActive(), *test_setup->m_node.mempool, txr, false /* bypass_limits */);
            assert(res.m_result_type == MempoolAcceptResult::ResultType::VALID);
        }
    }

    bench.run([&] {
        PrepareBlock(test_setup->m_node, P2WSH_OP_TRUE);
    });
}

BENCHMARK(AssembleBlock);
<|endoftext|>


<commit_before>#include "cinder/app/AppNative.h"
#include "cinder/gl/gl.h"
#include "cinder/System.h"

#if CINDER_VERSION >= 807
	#include "cinder/app/RendererGl.h"
	#include "cinder/Log.h"
#endif

#include "cidart/VM.h"
#include "cidart/Script.h"
#include "cidart/Types.h"
#include "cidart/Debug.h"

#include "Resources.h"

using namespace ci;
using namespace ci::app;
using namespace std;

struct BreathingRect {
	vec2	pos;
	vec2	size;
	ColorA	color;
	float   speed;
	float	breath;
	float   seed;
};

class DartFieldsApp : public AppNative {
  public:
	void setup() override;
	void mouseDown( MouseEvent event ) override;
	void keyDown( KeyEvent event ) override;
	void update() override;
	void draw() override;

	void loadScript();

	cidart::ScriptRef	mScript;

	std::vector<BreathingRect>	mBreathingRects;
};

void DartFieldsApp::setup()
{
	cidart::VM::setCinderDartScriptDataSource( loadResource( CIDART_RES_CINDER_DART ) );
	cidart::VM::setSnapshotBinDataSource( loadResource( CIDART_RES_SNAPSHOT_BIN ) );
	loadScript();

	// setup rendering
	gl::enableAlphaBlending();
}

void DartFieldsApp::loadScript()
{
	try {
		mScript = cidart::Script::create( loadAsset( "main.dart" ) );
	}
	catch( Exception &exc ) {
		CI_LOG_E( "exception of type: " << System::demangleTypeName( typeid( exc ).name() ) << ", what: " << exc.what() );
	}
}

void DartFieldsApp::mouseDown( MouseEvent event )
{
	// Before calling into the script, you must enter into 'dart scope'.
	// This way, you will have access to the handle it returns, and all resources will be freed at the end of the function.
	cidart::DartScope  enterScope;

	Dart_Handle handle = mScript->invoke( "makeBreathingRect" );

	BreathingRect br;
	br.pos = getMousePos() - getWindowPos();
	br.breath = 0;
	br.size = cidart::getField<vec2>( handle, "size" );
	br.color = cidart::getField<ColorA>( handle, "color" );
	br.speed = cidart::getField<float>( handle, "speed" );
	br.seed = cidart::getField<float>( handle, "seed" );

	mBreathingRects.push_back( br );
}

void DartFieldsApp::keyDown( KeyEvent event )
{
	if( event.getChar() == 'r' ) // reload script
		loadScript();
	if( event.getChar() == 'c' ) // clear existing objects
		mBreathingRects.clear();
}

void DartFieldsApp::update()
{
	for( auto &br : mBreathingRects )
		br.breath = 0.7f + sinf( br.speed + getElapsedSeconds() + br.seed * 1000 ) * 0.3f;
}

void DartFieldsApp::draw()
{
	gl::clear();

	for( const auto &br : mBreathingRects ) {
		gl::color( br.color );

		vec2 size2 = ( br.size * br.breath ) / 2;
		Rectf rect( br.pos.x - size2.x, br.pos.y - size2.y, br.pos.x + size2.x, br.pos.y + size2.y );
		gl::drawSolidRect( rect );
	}
}

CINDER_APP_NATIVE( DartFieldsApp, RendererGl )
<commit_msg>fix glm compile error on windows<commit_after>#include "cinder/app/AppNative.h"
#include "cinder/gl/gl.h"
#include "cinder/System.h"

#if CINDER_VERSION >= 807
	#include "cinder/app/RendererGl.h"
	#include "cinder/Log.h"
#endif

#include "cidart/VM.h"
#include "cidart/Script.h"
#include "cidart/Types.h"
#include "cidart/Debug.h"

#include "Resources.h"

using namespace ci;
using namespace ci::app;
using namespace std;

struct BreathingRect {
	vec2	pos;
	vec2	size;
	ColorA	color;
	float   speed;
	float	breath;
	float   seed;
};

class DartFieldsApp : public AppNative {
  public:
	void setup() override;
	void mouseDown( MouseEvent event ) override;
	void keyDown( KeyEvent event ) override;
	void update() override;
	void draw() override;

	void loadScript();

	cidart::ScriptRef	mScript;

	std::vector<BreathingRect>	mBreathingRects;
};

void DartFieldsApp::setup()
{
	cidart::VM::setCinderDartScriptDataSource( loadResource( CIDART_RES_CINDER_DART ) );
	cidart::VM::setSnapshotBinDataSource( loadResource( CIDART_RES_SNAPSHOT_BIN ) );
	loadScript();

	// setup rendering
	gl::enableAlphaBlending();
}

void DartFieldsApp::loadScript()
{
	try {
		mScript = cidart::Script::create( loadAsset( "main.dart" ) );
	}
	catch( Exception &exc ) {
		CI_LOG_E( "exception of type: " << System::demangleTypeName( typeid( exc ).name() ) << ", what: " << exc.what() );
	}
}

void DartFieldsApp::mouseDown( MouseEvent event )
{
	// Before calling into the script, you must enter into 'dart scope'.
	// This way, you will have access to the handle it returns, and all resources will be freed at the end of the function.
	cidart::DartScope  enterScope;

	Dart_Handle handle = mScript->invoke( "makeBreathingRect" );

	BreathingRect br;
	br.pos = getMousePos() - getWindowPos();
	br.breath = 0;
	br.size = cidart::getField<vec2>( handle, "size" );
	br.color = cidart::getField<ColorA>( handle, "color" );
	br.speed = cidart::getField<float>( handle, "speed" );
	br.seed = cidart::getField<float>( handle, "seed" );

	mBreathingRects.push_back( br );
}

void DartFieldsApp::keyDown( KeyEvent event )
{
	if( event.getChar() == 'r' ) // reload script
		loadScript();
	if( event.getChar() == 'c' ) // clear existing objects
		mBreathingRects.clear();
}

void DartFieldsApp::update()
{
	for( auto &br : mBreathingRects )
		br.breath = 0.7f + sinf( br.speed + getElapsedSeconds() + br.seed * 1000 ) * 0.3f;
}

void DartFieldsApp::draw()
{
	gl::clear();

	for( const auto &br : mBreathingRects ) {
		gl::color( br.color );

		vec2 size2 = ( br.size * br.breath ) / 2.0f;
		Rectf rect( br.pos.x - size2.x, br.pos.y - size2.y, br.pos.x + size2.x, br.pos.y + size2.y );
		gl::drawSolidRect( rect );
	}
}

CINDER_APP_NATIVE( DartFieldsApp, RendererGl )
<|endoftext|>


<commit_before><commit_msg>Append kernel signature to the log area in the SAL_INFO dump of its source<commit_after><|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 3.
 *
 *
 *    GNU Lesser General Public License Version 3
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

/* Currently the "all" installer has a bit over 100 UI languages, and
 * I doubt it will grow a lot over that.
 */
#define MAX_LANGUAGES 200

#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0500
#undef WINVER
#define WINVER 0x0500

#include <windows.h>
#include <msiquery.h>
#include <malloc.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sal/macros.h>
#include <systools/win32/uwinapi.h>

static const char *
langid_to_string( LANGID langid, int *have_default_lang )
{
    /* Map from LANGID to string. The languages below are now in
     * alphabetical order of codes as in
     * setup_native/source/win32/msi-encodinglist.txt. Only the
     * language part is returned in the string.
     */
    switch (PRIMARYLANGID (langid)) {
    case LANG_ENGLISH:
        if (have_default_lang != NULL &&
            langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
            *have_default_lang = 1;
        return "en";
#define CASE(name, primary) \
        case LANG_##primary: return #name
    CASE(af, AFRIKAANS);
    CASE(am, AMHARIC);
    CASE(ar, ARABIC);
    CASE(as, ASSAMESE);
    CASE(be, BELARUSIAN);
    CASE(bg, BULGARIAN);
    CASE(bn, BENGALI);
    CASE(br, BRETON);
    CASE(ca, CATALAN);
    CASE(cs, CZECH);
    CASE(cy, WELSH);
    CASE(da, DANISH);
    CASE(de, GERMAN);
    CASE(el, GREEK);
    CASE(es, SPANISH);
    CASE(et, ESTONIAN);
    CASE(eu, BASQUE);
    CASE(fa, FARSI);
    CASE(fi, FINNISH);
    CASE(fo, FAEROESE);
    CASE(fr, FRENCH);
    CASE(ga, IRISH);
    CASE(gl, GALICIAN);
    CASE(gu, GUJARATI);
    CASE(he, HEBREW);
    CASE(hi, HINDI);
    CASE(hu, HUNGARIAN);
    CASE(hy, ARMENIAN);
    CASE(id, INDONESIAN);
    CASE(is, ICELANDIC);
    CASE(it, ITALIAN);
    CASE(ja, JAPANESE);
    CASE(ka, GEORGIAN);
    CASE(km, KHMER);
    CASE(kn, KANNADA);
    CASE(ko, KOREAN);
    CASE(ks, KASHMIRI);
    CASE(lo, LAO);
    CASE(lt, LITHUANIAN);
    CASE(lv, LATVIAN);
    CASE(mk, MACEDONIAN);
    CASE(ml, MALAYALAM);
    CASE(mn, MONGOLIAN);
    CASE(mr, MARATHI);
    CASE(ms, MALAY);
    CASE(mt, MALTESE);
    CASE(ne, NEPALI);
    CASE(nl, DUTCH);
    CASE(ns, SOTHO);
    CASE(or, ORIYA);
    CASE(pa, PUNJABI);
    CASE(pl, POLISH);
    CASE(pt, PORTUGUESE);
    CASE(rm, ROMANSH);
    CASE(ro, ROMANIAN);
    CASE(ru, RUSSIAN);
    CASE(rw, KINYARWANDA);
    CASE(sa, SANSKRIT);
    CASE(sb, UPPER_SORBIAN);
    CASE(sd, SINDHI);
    CASE(sk, SLOVAK);
    CASE(sl, SLOVENIAN);
    CASE(sq, ALBANIAN);
    CASE(sv, SWEDISH);
    CASE(sw, SWAHILI);
    CASE(ta, TAMIL);
    CASE(te, TELUGU);
    CASE(tg, TAJIK);
    CASE(th, THAI);
    CASE(ti, TIGRIGNA);
    CASE(tn, TSWANA);
    CASE(tr, TURKISH);
    CASE(tt, TATAR);
    CASE(uk, UKRAINIAN);
    CASE(ur, URDU);
    CASE(uz, UZBEK);
    CASE(vi, VIETNAMESE);
    CASE(xh, XHOSA);
    CASE(zh, CHINESE);
    CASE(zu, ZULU);
#undef CASE
    /* Special cases */
    default:
        switch (langid) {
        case MAKELANGID(LANG_SERBIAN, 0x05): return "bs";
#define CASE(name, primary, sub) \
        case MAKELANGID(LANG_##primary, SUBLANG_##sub): return #name

        CASE(hr, SERBIAN, DEFAULT);
        CASE(nb, NORWEGIAN, NORWEGIAN_BOKMAL);
        CASE(nn, NORWEGIAN, NORWEGIAN_NYNORSK);
        CASE(sh, SERBIAN, SERBIAN_LATIN);
        CASE(sr, SERBIAN, SERBIAN_CYRILLIC);
#undef CASE
        default: return "";
        }
    }
}

/* Here we collect the UI languages present on the system;
 * MAX_LANGUAGES is certainly enough for that
 */
static const char *ui_langs[MAX_LANGUAGES];
static int num_ui_langs = 0;

BOOL CALLBACK
enum_ui_lang_proc (LPTSTR language, LONG_PTR /* unused_lParam */)
{
    long langid = strtol(language, NULL, 16);
    if (langid > 0xFFFF)
        return TRUE;
    ui_langs[num_ui_langs] = langid_to_string((LANGID) langid, NULL);
    num_ui_langs++;
    if (num_ui_langs == SAL_N_ELEMENTS(ui_langs) )
        return FALSE;
    return TRUE;
}

static BOOL
present_in_ui_langs(const char *lang)
{
    for (int i = 0; i < num_ui_langs; i++)
        if (memcmp (ui_langs[i], lang, 2) == 0)
            return TRUE;
    return FALSE;
}

extern "C" UINT __stdcall SelectLanguage( MSIHANDLE handle )
{
    char feature[100];
    MSIHANDLE database, view, record;
    DWORD length;
    int nlangs = 0;
    char langs[MAX_LANGUAGES][6];

    database = MsiGetActiveDatabase(handle);

    if (MsiDatabaseOpenViewA(database, "SELECT Feature from Feature WHERE Feature_Parent = 'gm_Langpack_Languageroot'", &view) != ERROR_SUCCESS) {
        MsiCloseHandle(database);
        return ERROR_SUCCESS;
    }

    if (MsiViewExecute(view, NULL) != ERROR_SUCCESS) {
        MsiCloseHandle(view);
        MsiCloseHandle(database);
        return ERROR_SUCCESS;
    }

    while (nlangs < MAX_LANGUAGES &&
           MsiViewFetch(view, &record) == ERROR_SUCCESS) {
        length = sizeof(feature);
        if (MsiRecordGetStringA(record, 1, feature, &length) != ERROR_SUCCESS) {
            MsiCloseHandle(record);
            MsiCloseHandle(view);
            MsiCloseHandle(database);
            return ERROR_SUCCESS;
        }

        /* Keep track of what languages are included in this installer, if
         * it is a multilanguage one.
         */
        if (strcmp(feature, "gm_Langpack_r_en_US") != 0)
            strcpy(langs[nlangs++], feature + strlen("gm_Langpack_r_"));

        MsiCloseHandle(record);
    }

    MsiCloseHandle(view);

    if (nlangs > 0) {
        /* Deselect those languages that don't match any of the UI languages
         * available on the system.
         */

        int i;
        int have_system_default_lang = 0;
        const char *system_default_lang = langid_to_string(GetSystemDefaultUILanguage(), &have_system_default_lang);
        const char *user_locale_lang = langid_to_string(LANGIDFROMLCID(GetThreadLocale()), NULL);

        EnumUILanguagesA(enum_ui_lang_proc, 0, 0);

        /* If one of the alternative languages in a multi-language installer
         * is the system default UI language, deselect those languages that
         * aren't among the UI languages available on the system.
         * (On most Windows installations, just one UI language is present,
         * which obviously is the same as the default UI language. But
         * we want to be generic.)
         * If none of the languages in a multi-language installer is the
         * system default UI language (this happens now in 2.4.0 where we
         * cannot put as many UI languages into the installer as we would
         * like, but only half a dozen: en-US,de,es,fr,it,pt-BR), pretend
         * that English is the system default UI language,
         * so that we will by default deselect everything except
         * English. We don't want to by default install all half dozen
         * languages for an unsuspecting user of a Finnish Windows, for
         * instance. Sigh.
         */
        if (system_default_lang[0]) {
            for (i = 0; i < nlangs; i++) {
                if (memcmp (system_default_lang, langs[i], 2) == 0) {
                    have_system_default_lang = 1;
                }
            }
        }

        if (!have_system_default_lang) {
            system_default_lang = "en";
            have_system_default_lang = 1;
        }
        if (have_system_default_lang) {
            for (i = 0; i < nlangs; i++) {
                if (memcmp(system_default_lang, langs[i], 2) != 0 &&
                    memcmp(user_locale_lang, langs[i], 2) != 0 &&
                    !present_in_ui_langs(langs[i])) {
                    UINT rc;
                    sprintf(feature, "gm_Langpack_r_%s", langs[i]);
                    rc = MsiSetFeatureStateA(handle, feature, INSTALLSTATE_ABSENT);
                }
            }
        }
    }

    MsiCloseHandle(database);

    return ERROR_SUCCESS;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>fdo#50509 MSI: UI language selection from command line (e.g. silent install)<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 3.
 *
 *
 *    GNU Lesser General Public License Version 3
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

/* Currently the "all" installer has a bit over 100 UI languages, and
 * I doubt it will grow a lot over that.
 */
#define MAX_LANGUAGES 200

#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0500
#undef WINVER
#define WINVER 0x0500

#include <windows.h>
#include <msiquery.h>
#include <malloc.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sal/macros.h>
#include <systools/win32/uwinapi.h>

BOOL GetMsiProp( MSIHANDLE hMSI, const char* pPropName, char** ppValue )
{
    DWORD sz = 0;
    if ( MsiGetProperty( hMSI, pPropName, "", &sz ) == ERROR_MORE_DATA ) {
        sz++;
        DWORD nbytes = sz * sizeof( char );
        char* buff = reinterpret_cast<char*>( malloc( nbytes ) );
        ZeroMemory( buff, nbytes );
        MsiGetProperty( hMSI, pPropName, buff, &sz );
        *ppValue = buff;
        return ( strlen(buff) > 0 );
    }
    return FALSE;
}

static const char *
langid_to_string( LANGID langid, int *have_default_lang )
{
    /* Map from LANGID to string. The languages below are now in
     * alphabetical order of codes as in
     * setup_native/source/win32/msi-encodinglist.txt. Only the
     * language part is returned in the string.
     */
    switch (PRIMARYLANGID (langid)) {
    case LANG_ENGLISH:
        if (have_default_lang != NULL &&
            langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
            *have_default_lang = 1;
        return "en";
#define CASE(name, primary) \
        case LANG_##primary: return #name
    CASE(af, AFRIKAANS);
    CASE(am, AMHARIC);
    CASE(ar, ARABIC);
    CASE(as, ASSAMESE);
    CASE(be, BELARUSIAN);
    CASE(bg, BULGARIAN);
    CASE(bn, BENGALI);
    CASE(br, BRETON);
    CASE(ca, CATALAN);
    CASE(cs, CZECH);
    CASE(cy, WELSH);
    CASE(da, DANISH);
    CASE(de, GERMAN);
    CASE(el, GREEK);
    CASE(es, SPANISH);
    CASE(et, ESTONIAN);
    CASE(eu, BASQUE);
    CASE(fa, FARSI);
    CASE(fi, FINNISH);
    CASE(fo, FAEROESE);
    CASE(fr, FRENCH);
    CASE(ga, IRISH);
    CASE(gl, GALICIAN);
    CASE(gu, GUJARATI);
    CASE(he, HEBREW);
    CASE(hi, HINDI);
    CASE(hu, HUNGARIAN);
    CASE(hy, ARMENIAN);
    CASE(id, INDONESIAN);
    CASE(is, ICELANDIC);
    CASE(it, ITALIAN);
    CASE(ja, JAPANESE);
    CASE(ka, GEORGIAN);
    CASE(km, KHMER);
    CASE(kn, KANNADA);
    CASE(ko, KOREAN);
    CASE(ks, KASHMIRI);
    CASE(lo, LAO);
    CASE(lt, LITHUANIAN);
    CASE(lv, LATVIAN);
    CASE(mk, MACEDONIAN);
    CASE(ml, MALAYALAM);
    CASE(mn, MONGOLIAN);
    CASE(mr, MARATHI);
    CASE(ms, MALAY);
    CASE(mt, MALTESE);
    CASE(ne, NEPALI);
    CASE(nl, DUTCH);
    CASE(ns, SOTHO);
    CASE(or, ORIYA);
    CASE(pa, PUNJABI);
    CASE(pl, POLISH);
    CASE(pt, PORTUGUESE);
    CASE(rm, ROMANSH);
    CASE(ro, ROMANIAN);
    CASE(ru, RUSSIAN);
    CASE(rw, KINYARWANDA);
    CASE(sa, SANSKRIT);
    CASE(sb, UPPER_SORBIAN);
    CASE(sd, SINDHI);
    CASE(sk, SLOVAK);
    CASE(sl, SLOVENIAN);
    CASE(sq, ALBANIAN);
    CASE(sv, SWEDISH);
    CASE(sw, SWAHILI);
    CASE(ta, TAMIL);
    CASE(te, TELUGU);
    CASE(tg, TAJIK);
    CASE(th, THAI);
    CASE(ti, TIGRIGNA);
    CASE(tn, TSWANA);
    CASE(tr, TURKISH);
    CASE(tt, TATAR);
    CASE(uk, UKRAINIAN);
    CASE(ur, URDU);
    CASE(uz, UZBEK);
    CASE(vi, VIETNAMESE);
    CASE(xh, XHOSA);
    CASE(zh, CHINESE);
    CASE(zu, ZULU);
#undef CASE
    /* Special cases */
    default:
        switch (langid) {
        case MAKELANGID(LANG_SERBIAN, 0x05): return "bs";
#define CASE(name, primary, sub) \
        case MAKELANGID(LANG_##primary, SUBLANG_##sub): return #name

        CASE(hr, SERBIAN, DEFAULT);
        CASE(nb, NORWEGIAN, NORWEGIAN_BOKMAL);
        CASE(nn, NORWEGIAN, NORWEGIAN_NYNORSK);
        CASE(sh, SERBIAN, SERBIAN_LATIN);
        CASE(sr, SERBIAN, SERBIAN_CYRILLIC);
#undef CASE
        default: return "";
        }
    }
}

/* Here we collect the UI languages present on the system;
 * MAX_LANGUAGES is certainly enough for that
 */
static const char *ui_langs[MAX_LANGUAGES];
static int num_ui_langs = 0;

BOOL CALLBACK
enum_ui_lang_proc (LPTSTR language, LONG_PTR /* unused_lParam */)
{
    long langid = strtol(language, NULL, 16);
    if (langid > 0xFFFF)
        return TRUE;
    ui_langs[num_ui_langs] = langid_to_string((LANGID) langid, NULL);
    num_ui_langs++;
    if (num_ui_langs == SAL_N_ELEMENTS(ui_langs) )
        return FALSE;
    return TRUE;
}

static BOOL
present_in_ui_langs(const char *lang)
{
    for (int i = 0; i < num_ui_langs; i++)
        if (memcmp (ui_langs[i], lang, ( strlen(ui_langs[i]) >= strlen(lang) ) ? strlen(lang) : strlen(ui_langs[i]) ) == 0)
            return TRUE;
    return FALSE;
}

extern "C" UINT __stdcall SelectLanguage( MSIHANDLE handle )
{
    char feature[100];
    MSIHANDLE database, view, record;
    DWORD length;
    int nlangs = 0;
    char langs[MAX_LANGUAGES][6];

    database = MsiGetActiveDatabase(handle);

    if (MsiDatabaseOpenViewA(database, "SELECT Feature from Feature WHERE Feature_Parent = 'gm_Langpack_Languageroot'", &view) != ERROR_SUCCESS) {
        MsiCloseHandle(database);
        return ERROR_SUCCESS;
    }

    if (MsiViewExecute(view, NULL) != ERROR_SUCCESS) {
        MsiCloseHandle(view);
        MsiCloseHandle(database);
        return ERROR_SUCCESS;
    }

    while (nlangs < MAX_LANGUAGES &&
           MsiViewFetch(view, &record) == ERROR_SUCCESS) {
        length = sizeof(feature);
        if (MsiRecordGetStringA(record, 1, feature, &length) != ERROR_SUCCESS) {
            MsiCloseHandle(record);
            MsiCloseHandle(view);
            MsiCloseHandle(database);
            return ERROR_SUCCESS;
        }

        /* Keep track of what languages are included in this installer, if
         * it is a multilanguage one.
         */
        if (strcmp(feature, "gm_Langpack_r_en_US") != 0)
            strcpy(langs[nlangs++], feature + strlen("gm_Langpack_r_"));

        MsiCloseHandle(record);
    }

    MsiCloseHandle(view);

    if (nlangs > 0) {
        int i;
        char* pVal = NULL;
        if ( (GetMsiProp( handle, "UI_LANGS", &pVal )) && pVal ) {
            /* user gave UI languages explicitely with UI_LANGS property */
            int sel_ui_lang = 0;
            strcpy(langs[nlangs++], "en_US");
            char *str_ptr;
            str_ptr = strtok(pVal, ",");
            for(; str_ptr != NULL ;) {
                ui_langs[num_ui_langs] = str_ptr;
                num_ui_langs++;
                str_ptr = strtok(NULL, ",");
            }
            for (i = 0; i < nlangs; i++) {
                if (!present_in_ui_langs(langs[i])) {
                    UINT rc;
                    sprintf(feature, "gm_Langpack_r_%s", langs[i]);
                    rc = MsiSetFeatureStateA(handle, feature, INSTALLSTATE_ABSENT);
                }
                else {
                    sel_ui_lang++;
                }
            }
            if ( sel_ui_lang == 0 ) {
                /* When UI_LANG property contains only languages that are not present
                 * in the installer, install at least en_US localization.
                 */
                MsiSetFeatureStateA(handle, "gm_Langpack_r_en_US", INSTALLSTATE_LOCAL);
            }
        }
        else {
            /* Deselect those languages that don't match any of the UI languages
             * available on the system.
             */

            int have_system_default_lang = 0;
            const char *system_default_lang = langid_to_string(GetSystemDefaultUILanguage(), &have_system_default_lang);
            const char *user_locale_lang = langid_to_string(LANGIDFROMLCID(GetThreadLocale()), NULL);

            EnumUILanguagesA(enum_ui_lang_proc, 0, 0);

            /* If one of the alternative languages in a multi-language installer
             * is the system default UI language, deselect those languages that
             * aren't among the UI languages available on the system.
             * (On most Windows installations, just one UI language is present,
             * which obviously is the same as the default UI language. But
             * we want to be generic.)
             * If none of the languages in a multi-language installer is the
             * system default UI language (this happens now in 2.4.0 where we
             * cannot put as many UI languages into the installer as we would
             * like, but only half a dozen: en-US,de,es,fr,it,pt-BR), pretend
             * that English is the system default UI language,
             * so that we will by default deselect everything except
             * English. We don't want to by default install all half dozen
             * languages for an unsuspecting user of a Finnish Windows, for
             * instance. Sigh.
             */
            if (system_default_lang[0]) {
                for (i = 0; i < nlangs; i++) {
                    if (memcmp (system_default_lang, langs[i], 2) == 0) {
                        have_system_default_lang = 1;
                    }
                }
            }

            if (!have_system_default_lang) {
                system_default_lang = "en";
                have_system_default_lang = 1;
            }
            if (have_system_default_lang) {
                for (i = 0; i < nlangs; i++) {
                    if (memcmp(system_default_lang, langs[i], 2) != 0 &&
                        memcmp(user_locale_lang, langs[i], 2) != 0 &&
                        !present_in_ui_langs(langs[i])) {
                        UINT rc;
                        sprintf(feature, "gm_Langpack_r_%s", langs[i]);
                        rc = MsiSetFeatureStateA(handle, feature, INSTALLSTATE_ABSENT);
                    }
                }
            }
        }
    }
    MsiCloseHandle(database);

    return ERROR_SUCCESS;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_path.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

typedef InProcessBrowserTest SessionRestoreTest;

#if !defined(OS_WIN)
// http://crbug.com/39476
#define RestoreOnNewWindowWithNoTabbedBrowsers \
        FLAKY_RestoreOnNewWindowWithNoTabbedBrowsers
#endif

// Makes sure when session restore is triggered in the same process we don't end
// up with an extra tab.
IN_PROC_BROWSER_TEST_F(SessionRestoreTest,
                       RestoreOnNewWindowWithNoTabbedBrowsers) {
  if (browser_defaults::kRestorePopups)
    return;

  const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html");
  GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                     FilePath(kTitle1File)));
  ui_test_utils::NavigateToURL(browser(), url);

  // Turn on session restore.
  SessionStartupPref::SetStartupPref(
      browser()->profile(),
      SessionStartupPref(SessionStartupPref::LAST));

  // Create a new popup.
  Profile* profile = browser()->profile();
  Browser* popup = Browser::CreateForPopup(profile);
  popup->window()->Show();

  // Close the browser.
  browser()->window()->Close();

  // Create a new window, which should trigger session restore.
  popup->NewWindow();

  Browser* new_browser = ui_test_utils::WaitForNewBrowser();

  ASSERT_TRUE(new_browser != NULL);

  // The browser should only have one tab.
  ASSERT_EQ(1, new_browser->tab_count());

  // And the first url should be url.
  EXPECT_EQ(url, new_browser->GetTabContentsAt(0)->GetURL());
}
<commit_msg>Disable SessionRestoreTest.RestoreOnNewWindowWithNoTabbedBrowsers on Mac and Linux since it crashes.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_path.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

typedef InProcessBrowserTest SessionRestoreTest;

#if !defined(OS_WIN)
// http://crbug.com/39476
#define RestoreOnNewWindowWithNoTabbedBrowsers \
        DISABLED_RestoreOnNewWindowWithNoTabbedBrowsers
#endif

// Makes sure when session restore is triggered in the same process we don't end
// up with an extra tab.
IN_PROC_BROWSER_TEST_F(SessionRestoreTest,
                       RestoreOnNewWindowWithNoTabbedBrowsers) {
  if (browser_defaults::kRestorePopups)
    return;

  const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html");
  GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                     FilePath(kTitle1File)));
  ui_test_utils::NavigateToURL(browser(), url);

  // Turn on session restore.
  SessionStartupPref::SetStartupPref(
      browser()->profile(),
      SessionStartupPref(SessionStartupPref::LAST));

  // Create a new popup.
  Profile* profile = browser()->profile();
  Browser* popup = Browser::CreateForPopup(profile);
  popup->window()->Show();

  // Close the browser.
  browser()->window()->Close();

  // Create a new window, which should trigger session restore.
  popup->NewWindow();

  Browser* new_browser = ui_test_utils::WaitForNewBrowser();

  ASSERT_TRUE(new_browser != NULL);

  // The browser should only have one tab.
  ASSERT_EQ(1, new_browser->tab_count());

  // And the first url should be url.
  EXPECT_EQ(url, new_browser->GetTabContentsAt(0)->GetURL());
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 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/ui/panels/panel_browser_titlebar_gtk.h"

#include "base/utf_string_conversions.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/gtk/custom_button.h"
#include "chrome/browser/ui/gtk/gtk_theme_service.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/gtk/gtk_theme_service.h"
#include "chrome/browser/ui/panels/panel.h"
#include "chrome/browser/ui/panels/panel_browser_window_gtk.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/gtk/gtk_compat.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/skia_utils_gtk.h"

namespace {

// Padding around the titlebar.
const int kPanelTitlebarPaddingTop = 7;
const int kPanelTitlebarPaddingBottom = 7;
const int kPanelTitlebarPaddingLeft = 4;
const int kPanelTitlebarPaddingRight = 9;

// Spacing between buttons of panel's titlebar.
const int kPanelButtonSpacing = 9;

// Spacing between the icon and the title text.
const int kPanelIconTitleSpacing = 9;

// Color used to draw title text under default theme.
const SkColor kTitleTextDefaultColor = SkColorSetRGB(0xf9, 0xf9, 0xf9);

// Markup used to paint the title with the desired font.
const char* const kTitleMarkupPrefix = "";
const char* const kTitleMarkupSuffix = "";

}  // namespace

PanelBrowserTitlebarGtk::PanelBrowserTitlebarGtk(
    PanelBrowserWindowGtk* browser_window, GtkWindow* window)
    : browser_window_(browser_window),
      window_(window),
      container_(NULL),
      titlebar_right_buttons_vbox_(NULL),
      titlebar_right_buttons_hbox_(NULL),
      icon_(NULL),
      title_(NULL),
      theme_service_(NULL) {
}

PanelBrowserTitlebarGtk::~PanelBrowserTitlebarGtk() {
}

void PanelBrowserTitlebarGtk::Init() {
  container_ = gtk_event_box_new();
  gtk_widget_set_name(container_, "chrome-panel-titlebar");
  gtk_event_box_set_visible_window(GTK_EVENT_BOX(container_), FALSE);

  // We use an alignment to control the titlebar paddings.
  GtkWidget* container_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
  gtk_container_add(GTK_CONTAINER(container_), container_alignment);
  gtk_alignment_set_padding(GTK_ALIGNMENT(container_alignment),
                            kPanelTitlebarPaddingTop,
                            kPanelTitlebarPaddingBottom,
                            kPanelTitlebarPaddingLeft,
                            kPanelTitlebarPaddingRight);

  // Add a container box.
  GtkWidget* container_hbox = gtk_hbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(container_alignment), container_hbox);

  g_signal_connect(window_, "window-state-event",
                   G_CALLBACK(OnWindowStateChangedThunk), this);

  // Add minimize/restore and close buttons. Panel buttons are always placed
  // on the right part of the titlebar.
  titlebar_right_buttons_vbox_ = gtk_vbox_new(FALSE, 0);
  gtk_box_pack_end(GTK_BOX(container_hbox), titlebar_right_buttons_vbox_,
                   FALSE, FALSE, 0);
  BuildButtons();

  // Add hbox for holding icon and title.
  GtkWidget* icon_title_hbox = gtk_hbox_new(FALSE, kPanelIconTitleSpacing);
  gtk_box_pack_start(GTK_BOX(container_hbox), icon_title_hbox, TRUE, TRUE, 0);

  // Add icon. We use the app logo as a placeholder image so the title doesn't
  // jump around.
  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  icon_ = gtk_image_new_from_pixbuf(rb.GetNativeImageNamed(
      IDR_PRODUCT_LOGO_16, ui::ResourceBundle::RTL_ENABLED).ToGdkPixbuf());
  g_object_set_data(G_OBJECT(icon_), "left-align-popup",
                    reinterpret_cast<void*>(true));
  gtk_box_pack_start(GTK_BOX(icon_title_hbox), icon_, FALSE, FALSE, 0);

  // Add title.
  title_ = gtk_label_new(NULL);
  gtk_label_set_ellipsize(GTK_LABEL(title_), PANGO_ELLIPSIZE_END);
  gtk_misc_set_alignment(GTK_MISC(title_), 0.0, 0.5);
  gtk_box_pack_start(GTK_BOX(icon_title_hbox), title_, TRUE, TRUE, 0);

  UpdateTitleAndIcon();

  theme_service_ = GtkThemeService::GetFrom(
      browser_window_->panel()->profile());
  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
                 content::Source<ThemeService>(theme_service_));
  theme_service_->InitThemesFor(this);

  gtk_widget_show_all(container_);
}

SkColor PanelBrowserTitlebarGtk::GetTextColor() const {
  if (browser_window_->UsingDefaultTheme())
    return kTitleTextDefaultColor;
  return theme_service_->GetColor(browser_window_->paint_state() ==
      PanelBrowserWindowGtk::PAINT_AS_ACTIVE ?
          ThemeService::COLOR_TAB_TEXT :
          ThemeService::COLOR_BACKGROUND_TAB_TEXT);
}

void PanelBrowserTitlebarGtk::BuildButtons() {
  minimize_button_.reset(CreateButton(panel::MINIMIZE_BUTTON));
  restore_button_.reset(CreateButton(panel::RESTORE_BUTTON));
  close_button_.reset(CreateButton(panel::CLOSE_BUTTON));

  // We control visibility of minimize and restore buttons.
  gtk_widget_set_no_show_all(minimize_button_->widget(), TRUE);
  gtk_widget_set_no_show_all(restore_button_->widget(), TRUE);

  // Now show the correct widgets in the two hierarchies.
  UpdateMinimizeRestoreButtonVisibility();
}

CustomDrawButton* PanelBrowserTitlebarGtk::CreateButton(
    panel::TitlebarButtonType button_type) {
  int normal_image_id;
  int pressed_image_id;
  int hover_image_id;
  int tooltip_id;
  GetButtonResources(button_type, &normal_image_id, &pressed_image_id,
                     &hover_image_id, &tooltip_id);

  CustomDrawButton* button = new CustomDrawButton(normal_image_id,
                                                  pressed_image_id,
                                                  hover_image_id,
                                                  0);
  gtk_widget_add_events(GTK_WIDGET(button->widget()), GDK_POINTER_MOTION_MASK);
  g_signal_connect(button->widget(), "clicked",
                   G_CALLBACK(OnButtonClickedThunk), this);

  std::string localized_tooltip = l10n_util::GetStringUTF8(tooltip_id);
  gtk_widget_set_tooltip_text(button->widget(),
                              localized_tooltip.c_str());

  GtkWidget* box = GetButtonHBox();
  gtk_box_pack_start(GTK_BOX(box), button->widget(), FALSE, FALSE, 0);
  return button;
}

void PanelBrowserTitlebarGtk::GetButtonResources(
    panel::TitlebarButtonType button_type,
    int* normal_image_id,
    int* pressed_image_id,
    int* hover_image_id,
    int* tooltip_id) const {
  switch (button_type) {
    case panel::CLOSE_BUTTON:
      *normal_image_id = IDR_PANEL_CLOSE;
      *pressed_image_id = IDR_PANEL_CLOSE_C;
      *hover_image_id = IDR_PANEL_CLOSE_H;
      *tooltip_id = IDS_PANEL_CLOSE_TOOLTIP;
      break;
    case panel::MINIMIZE_BUTTON:
      *normal_image_id = IDR_PANEL_MINIMIZE;
      *pressed_image_id = IDR_PANEL_MINIMIZE_C;
      *hover_image_id = IDR_PANEL_MINIMIZE_H;
      *tooltip_id = IDS_PANEL_MINIMIZE_TOOLTIP;
      break;
    case panel::RESTORE_BUTTON:
      *normal_image_id = IDR_PANEL_RESTORE;
      *pressed_image_id = IDR_PANEL_RESTORE_C;
      *hover_image_id = IDR_PANEL_RESTORE_H;
      *tooltip_id = IDS_PANEL_RESTORE_TOOLTIP;
      break;
  }
}

GtkWidget* PanelBrowserTitlebarGtk::GetButtonHBox() {
  if (!titlebar_right_buttons_hbox_) {
    // We put the minimize/restore/close buttons in a vbox so they are top
    // aligned (up to padding) and don't vertically stretch.
    titlebar_right_buttons_hbox_ = gtk_hbox_new(FALSE, kPanelButtonSpacing);
    gtk_box_pack_start(GTK_BOX(titlebar_right_buttons_vbox_),
                       titlebar_right_buttons_hbox_, FALSE, FALSE, 0);
  }

  return titlebar_right_buttons_hbox_;
}

void PanelBrowserTitlebarGtk::UpdateCustomFrame(bool use_custom_frame) {
  // Nothing to do.
}

void PanelBrowserTitlebarGtk::UpdateTitleAndIcon() {
  std::string title_text =
      UTF16ToUTF8(browser_window_->panel()->GetWindowTitle());

  // Add the markup to show the title in the desired font.
  gchar* escaped_title_text = g_markup_escape_text(title_text.c_str(), -1);
  gchar* title_text_with_markup = g_strconcat(kTitleMarkupPrefix,
                                              escaped_title_text,
                                              kTitleMarkupSuffix,
                                              NULL);
  gtk_label_set_markup(GTK_LABEL(title_), title_text_with_markup);
  g_free(escaped_title_text);
  g_free(title_text_with_markup);
}

void PanelBrowserTitlebarGtk::UpdateThrobber(
    content::WebContents* web_contents) {
  if (web_contents && web_contents->IsLoading()) {
    GdkPixbuf* icon_pixbuf =
        throbber_.GetNextFrame(web_contents->IsWaitingForResponse());
    gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), icon_pixbuf);
  } else {
    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();

    SkBitmap icon = browser_window_->panel()->GetCurrentPageIcon();
    if (icon.empty()) {
      // Fallback to the Chromium icon if the page has no icon.
      gtk_image_set_from_pixbuf(GTK_IMAGE(icon_),
          rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToGdkPixbuf());
    } else {
      GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(icon);
      gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), icon_pixbuf);
      g_object_unref(icon_pixbuf);
    }

    throbber_.Reset();
  }
}

void PanelBrowserTitlebarGtk::ShowContextMenu(GdkEventButton* event) {
  // Panel does not show any context menu.
}

void PanelBrowserTitlebarGtk::UpdateTextColor() {
  GdkColor text_color = gfx::SkColorToGdkColor(GetTextColor());
  gtk_util::SetLabelColor(title_, &text_color);
}

void PanelBrowserTitlebarGtk::UpdateMinimizeRestoreButtonVisibility() {
  Panel* panel = browser_window_->panel();
  gtk_widget_set_visible(minimize_button_->widget(), panel->CanMinimize());
  gtk_widget_set_visible(restore_button_->widget(), panel->CanRestore());
}

gboolean PanelBrowserTitlebarGtk::OnWindowStateChanged(
    GtkWindow* window, GdkEventWindowState* event) {
  UpdateTextColor();
  return FALSE;
}

void PanelBrowserTitlebarGtk::OnButtonClicked(GtkWidget* button) {
  if (close_button_->widget() == button) {
    browser_window_->panel()->Close();
    return;
  }

  GdkEvent* event = gtk_get_current_event();
  DCHECK(event && event->type == GDK_BUTTON_RELEASE);

  if (minimize_button_->widget() == button) {
    browser_window_->panel()->OnMinimizeButtonClicked(
        (event->button.state & GDK_CONTROL_MASK) ?
            panel::APPLY_TO_ALL : panel::NO_MODIFIER);
  } else if (restore_button_->widget() == button) {
    browser_window_->panel()->OnRestoreButtonClicked(
        (event->button.state & GDK_CONTROL_MASK) ?
            panel::APPLY_TO_ALL : panel::NO_MODIFIER);
  }

  gdk_event_free(event);
}

void PanelBrowserTitlebarGtk::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_BROWSER_THEME_CHANGED:
      UpdateTextColor();
      break;
    default:
      NOTREACHED();
  }
}

void PanelBrowserTitlebarGtk::SendEnterNotifyToCloseButtonIfUnderMouse() {
  if (!close_button())
    return;

  gint x;
  gint y;
  GtkAllocation widget_allocation = close_button()->WidgetAllocation();
  gtk_widget_get_pointer(GTK_WIDGET(close_button()->widget()), &x, &y);

  gfx::Rect button_rect(0, 0, widget_allocation.width,
                        widget_allocation.height);
  if (!button_rect.Contains(x, y)) {
    // Mouse is not over the close button.
    return;
  }

  // Create and emit an enter-notify-event on close button.
  GValue return_value;
  return_value.g_type = G_TYPE_BOOLEAN;
  g_value_set_boolean(&return_value, false);

  GdkEvent* event = gdk_event_new(GDK_ENTER_NOTIFY);
  event->crossing.window =
      gtk_button_get_event_window(GTK_BUTTON(close_button()->widget()));
  event->crossing.send_event = FALSE;
  event->crossing.subwindow = gtk_widget_get_window(close_button()->widget());
  event->crossing.time = gtk_util::XTimeNow();
  event->crossing.x = x;
  event->crossing.y = y;
  event->crossing.x_root = widget_allocation.x;
  event->crossing.y_root = widget_allocation.y;
  event->crossing.mode = GDK_CROSSING_NORMAL;
  event->crossing.detail = GDK_NOTIFY_ANCESTOR;
  event->crossing.focus = true;
  event->crossing.state = 0;

  g_signal_emit_by_name(GTK_OBJECT(close_button()->widget()),
                        "enter-notify-event", event,
                        &return_value);
}

GtkWidget* PanelBrowserTitlebarGtk::widget() const {
  return container_;
}

void PanelBrowserTitlebarGtk::set_window(GtkWindow* window) {
  window_ = window;
}

AvatarMenuButtonGtk* PanelBrowserTitlebarGtk::avatar_button() const {
  // Not supported in panel.
  return NULL;
}
<commit_msg>Initialize variables PanelBrowserTitlebarGtk::CreateButton() to make g++ 4.6 happy.<commit_after>// Copyright (c) 2012 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/ui/panels/panel_browser_titlebar_gtk.h"

#include "base/utf_string_conversions.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/gtk/custom_button.h"
#include "chrome/browser/ui/gtk/gtk_theme_service.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/gtk/gtk_theme_service.h"
#include "chrome/browser/ui/panels/panel.h"
#include "chrome/browser/ui/panels/panel_browser_window_gtk.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/gtk/gtk_compat.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/skia_utils_gtk.h"

namespace {

// Padding around the titlebar.
const int kPanelTitlebarPaddingTop = 7;
const int kPanelTitlebarPaddingBottom = 7;
const int kPanelTitlebarPaddingLeft = 4;
const int kPanelTitlebarPaddingRight = 9;

// Spacing between buttons of panel's titlebar.
const int kPanelButtonSpacing = 9;

// Spacing between the icon and the title text.
const int kPanelIconTitleSpacing = 9;

// Color used to draw title text under default theme.
const SkColor kTitleTextDefaultColor = SkColorSetRGB(0xf9, 0xf9, 0xf9);

// Markup used to paint the title with the desired font.
const char* const kTitleMarkupPrefix = "";
const char* const kTitleMarkupSuffix = "";

}  // namespace

PanelBrowserTitlebarGtk::PanelBrowserTitlebarGtk(
    PanelBrowserWindowGtk* browser_window, GtkWindow* window)
    : browser_window_(browser_window),
      window_(window),
      container_(NULL),
      titlebar_right_buttons_vbox_(NULL),
      titlebar_right_buttons_hbox_(NULL),
      icon_(NULL),
      title_(NULL),
      theme_service_(NULL) {
}

PanelBrowserTitlebarGtk::~PanelBrowserTitlebarGtk() {
}

void PanelBrowserTitlebarGtk::Init() {
  container_ = gtk_event_box_new();
  gtk_widget_set_name(container_, "chrome-panel-titlebar");
  gtk_event_box_set_visible_window(GTK_EVENT_BOX(container_), FALSE);

  // We use an alignment to control the titlebar paddings.
  GtkWidget* container_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
  gtk_container_add(GTK_CONTAINER(container_), container_alignment);
  gtk_alignment_set_padding(GTK_ALIGNMENT(container_alignment),
                            kPanelTitlebarPaddingTop,
                            kPanelTitlebarPaddingBottom,
                            kPanelTitlebarPaddingLeft,
                            kPanelTitlebarPaddingRight);

  // Add a container box.
  GtkWidget* container_hbox = gtk_hbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(container_alignment), container_hbox);

  g_signal_connect(window_, "window-state-event",
                   G_CALLBACK(OnWindowStateChangedThunk), this);

  // Add minimize/restore and close buttons. Panel buttons are always placed
  // on the right part of the titlebar.
  titlebar_right_buttons_vbox_ = gtk_vbox_new(FALSE, 0);
  gtk_box_pack_end(GTK_BOX(container_hbox), titlebar_right_buttons_vbox_,
                   FALSE, FALSE, 0);
  BuildButtons();

  // Add hbox for holding icon and title.
  GtkWidget* icon_title_hbox = gtk_hbox_new(FALSE, kPanelIconTitleSpacing);
  gtk_box_pack_start(GTK_BOX(container_hbox), icon_title_hbox, TRUE, TRUE, 0);

  // Add icon. We use the app logo as a placeholder image so the title doesn't
  // jump around.
  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  icon_ = gtk_image_new_from_pixbuf(rb.GetNativeImageNamed(
      IDR_PRODUCT_LOGO_16, ui::ResourceBundle::RTL_ENABLED).ToGdkPixbuf());
  g_object_set_data(G_OBJECT(icon_), "left-align-popup",
                    reinterpret_cast<void*>(true));
  gtk_box_pack_start(GTK_BOX(icon_title_hbox), icon_, FALSE, FALSE, 0);

  // Add title.
  title_ = gtk_label_new(NULL);
  gtk_label_set_ellipsize(GTK_LABEL(title_), PANGO_ELLIPSIZE_END);
  gtk_misc_set_alignment(GTK_MISC(title_), 0.0, 0.5);
  gtk_box_pack_start(GTK_BOX(icon_title_hbox), title_, TRUE, TRUE, 0);

  UpdateTitleAndIcon();

  theme_service_ = GtkThemeService::GetFrom(
      browser_window_->panel()->profile());
  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
                 content::Source<ThemeService>(theme_service_));
  theme_service_->InitThemesFor(this);

  gtk_widget_show_all(container_);
}

SkColor PanelBrowserTitlebarGtk::GetTextColor() const {
  if (browser_window_->UsingDefaultTheme())
    return kTitleTextDefaultColor;
  return theme_service_->GetColor(browser_window_->paint_state() ==
      PanelBrowserWindowGtk::PAINT_AS_ACTIVE ?
          ThemeService::COLOR_TAB_TEXT :
          ThemeService::COLOR_BACKGROUND_TAB_TEXT);
}

void PanelBrowserTitlebarGtk::BuildButtons() {
  minimize_button_.reset(CreateButton(panel::MINIMIZE_BUTTON));
  restore_button_.reset(CreateButton(panel::RESTORE_BUTTON));
  close_button_.reset(CreateButton(panel::CLOSE_BUTTON));

  // We control visibility of minimize and restore buttons.
  gtk_widget_set_no_show_all(minimize_button_->widget(), TRUE);
  gtk_widget_set_no_show_all(restore_button_->widget(), TRUE);

  // Now show the correct widgets in the two hierarchies.
  UpdateMinimizeRestoreButtonVisibility();
}

CustomDrawButton* PanelBrowserTitlebarGtk::CreateButton(
    panel::TitlebarButtonType button_type) {
  int normal_image_id = -1;
  int pressed_image_id = -1;
  int hover_image_id = -1;
  int tooltip_id = -1;
  GetButtonResources(button_type, &normal_image_id, &pressed_image_id,
                     &hover_image_id, &tooltip_id);

  CustomDrawButton* button = new CustomDrawButton(normal_image_id,
                                                  pressed_image_id,
                                                  hover_image_id,
                                                  0);
  gtk_widget_add_events(GTK_WIDGET(button->widget()), GDK_POINTER_MOTION_MASK);
  g_signal_connect(button->widget(), "clicked",
                   G_CALLBACK(OnButtonClickedThunk), this);

  std::string localized_tooltip = l10n_util::GetStringUTF8(tooltip_id);
  gtk_widget_set_tooltip_text(button->widget(),
                              localized_tooltip.c_str());

  GtkWidget* box = GetButtonHBox();
  gtk_box_pack_start(GTK_BOX(box), button->widget(), FALSE, FALSE, 0);
  return button;
}

void PanelBrowserTitlebarGtk::GetButtonResources(
    panel::TitlebarButtonType button_type,
    int* normal_image_id,
    int* pressed_image_id,
    int* hover_image_id,
    int* tooltip_id) const {
  switch (button_type) {
    case panel::CLOSE_BUTTON:
      *normal_image_id = IDR_PANEL_CLOSE;
      *pressed_image_id = IDR_PANEL_CLOSE_C;
      *hover_image_id = IDR_PANEL_CLOSE_H;
      *tooltip_id = IDS_PANEL_CLOSE_TOOLTIP;
      break;
    case panel::MINIMIZE_BUTTON:
      *normal_image_id = IDR_PANEL_MINIMIZE;
      *pressed_image_id = IDR_PANEL_MINIMIZE_C;
      *hover_image_id = IDR_PANEL_MINIMIZE_H;
      *tooltip_id = IDS_PANEL_MINIMIZE_TOOLTIP;
      break;
    case panel::RESTORE_BUTTON:
      *normal_image_id = IDR_PANEL_RESTORE;
      *pressed_image_id = IDR_PANEL_RESTORE_C;
      *hover_image_id = IDR_PANEL_RESTORE_H;
      *tooltip_id = IDS_PANEL_RESTORE_TOOLTIP;
      break;
  }
}

GtkWidget* PanelBrowserTitlebarGtk::GetButtonHBox() {
  if (!titlebar_right_buttons_hbox_) {
    // We put the minimize/restore/close buttons in a vbox so they are top
    // aligned (up to padding) and don't vertically stretch.
    titlebar_right_buttons_hbox_ = gtk_hbox_new(FALSE, kPanelButtonSpacing);
    gtk_box_pack_start(GTK_BOX(titlebar_right_buttons_vbox_),
                       titlebar_right_buttons_hbox_, FALSE, FALSE, 0);
  }

  return titlebar_right_buttons_hbox_;
}

void PanelBrowserTitlebarGtk::UpdateCustomFrame(bool use_custom_frame) {
  // Nothing to do.
}

void PanelBrowserTitlebarGtk::UpdateTitleAndIcon() {
  std::string title_text =
      UTF16ToUTF8(browser_window_->panel()->GetWindowTitle());

  // Add the markup to show the title in the desired font.
  gchar* escaped_title_text = g_markup_escape_text(title_text.c_str(), -1);
  gchar* title_text_with_markup = g_strconcat(kTitleMarkupPrefix,
                                              escaped_title_text,
                                              kTitleMarkupSuffix,
                                              NULL);
  gtk_label_set_markup(GTK_LABEL(title_), title_text_with_markup);
  g_free(escaped_title_text);
  g_free(title_text_with_markup);
}

void PanelBrowserTitlebarGtk::UpdateThrobber(
    content::WebContents* web_contents) {
  if (web_contents && web_contents->IsLoading()) {
    GdkPixbuf* icon_pixbuf =
        throbber_.GetNextFrame(web_contents->IsWaitingForResponse());
    gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), icon_pixbuf);
  } else {
    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();

    SkBitmap icon = browser_window_->panel()->GetCurrentPageIcon();
    if (icon.empty()) {
      // Fallback to the Chromium icon if the page has no icon.
      gtk_image_set_from_pixbuf(GTK_IMAGE(icon_),
          rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToGdkPixbuf());
    } else {
      GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(icon);
      gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), icon_pixbuf);
      g_object_unref(icon_pixbuf);
    }

    throbber_.Reset();
  }
}

void PanelBrowserTitlebarGtk::ShowContextMenu(GdkEventButton* event) {
  // Panel does not show any context menu.
}

void PanelBrowserTitlebarGtk::UpdateTextColor() {
  GdkColor text_color = gfx::SkColorToGdkColor(GetTextColor());
  gtk_util::SetLabelColor(title_, &text_color);
}

void PanelBrowserTitlebarGtk::UpdateMinimizeRestoreButtonVisibility() {
  Panel* panel = browser_window_->panel();
  gtk_widget_set_visible(minimize_button_->widget(), panel->CanMinimize());
  gtk_widget_set_visible(restore_button_->widget(), panel->CanRestore());
}

gboolean PanelBrowserTitlebarGtk::OnWindowStateChanged(
    GtkWindow* window, GdkEventWindowState* event) {
  UpdateTextColor();
  return FALSE;
}

void PanelBrowserTitlebarGtk::OnButtonClicked(GtkWidget* button) {
  if (close_button_->widget() == button) {
    browser_window_->panel()->Close();
    return;
  }

  GdkEvent* event = gtk_get_current_event();
  DCHECK(event && event->type == GDK_BUTTON_RELEASE);

  if (minimize_button_->widget() == button) {
    browser_window_->panel()->OnMinimizeButtonClicked(
        (event->button.state & GDK_CONTROL_MASK) ?
            panel::APPLY_TO_ALL : panel::NO_MODIFIER);
  } else if (restore_button_->widget() == button) {
    browser_window_->panel()->OnRestoreButtonClicked(
        (event->button.state & GDK_CONTROL_MASK) ?
            panel::APPLY_TO_ALL : panel::NO_MODIFIER);
  }

  gdk_event_free(event);
}

void PanelBrowserTitlebarGtk::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_BROWSER_THEME_CHANGED:
      UpdateTextColor();
      break;
    default:
      NOTREACHED();
  }
}

void PanelBrowserTitlebarGtk::SendEnterNotifyToCloseButtonIfUnderMouse() {
  if (!close_button())
    return;

  gint x;
  gint y;
  GtkAllocation widget_allocation = close_button()->WidgetAllocation();
  gtk_widget_get_pointer(GTK_WIDGET(close_button()->widget()), &x, &y);

  gfx::Rect button_rect(0, 0, widget_allocation.width,
                        widget_allocation.height);
  if (!button_rect.Contains(x, y)) {
    // Mouse is not over the close button.
    return;
  }

  // Create and emit an enter-notify-event on close button.
  GValue return_value;
  return_value.g_type = G_TYPE_BOOLEAN;
  g_value_set_boolean(&return_value, false);

  GdkEvent* event = gdk_event_new(GDK_ENTER_NOTIFY);
  event->crossing.window =
      gtk_button_get_event_window(GTK_BUTTON(close_button()->widget()));
  event->crossing.send_event = FALSE;
  event->crossing.subwindow = gtk_widget_get_window(close_button()->widget());
  event->crossing.time = gtk_util::XTimeNow();
  event->crossing.x = x;
  event->crossing.y = y;
  event->crossing.x_root = widget_allocation.x;
  event->crossing.y_root = widget_allocation.y;
  event->crossing.mode = GDK_CROSSING_NORMAL;
  event->crossing.detail = GDK_NOTIFY_ANCESTOR;
  event->crossing.focus = true;
  event->crossing.state = 0;

  g_signal_emit_by_name(GTK_OBJECT(close_button()->widget()),
                        "enter-notify-event", event,
                        &return_value);
}

GtkWidget* PanelBrowserTitlebarGtk::widget() const {
  return container_;
}

void PanelBrowserTitlebarGtk::set_window(GtkWindow* window) {
  window_ = window;
}

AvatarMenuButtonGtk* PanelBrowserTitlebarGtk::avatar_button() const {
  // Not supported in panel.
  return NULL;
}
<|endoftext|>