<commit_before>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <Debugger.h>

#include <DebuggerIO.h>
#include <LocalIO.h>
#include <SerialIO.h>

#include <utilities/StaticString.h>

#include <processor/Processor.h>
#include <machine/Machine.h>

#include <Log.h>
#include <utilities/utility.h>

#include <graphics/GraphicsService.h>

static size_t newlineCount(const char *pString)
{
  size_t nNewlines = 0;
  while (*pString != '\0')
    if (*pString++ == '\n')
      ++nNewlines;

  return nNewlines;
}

// TODO: We might want a separate parameter for a stacktrace/register dump
void _panic( const char* msg, DebuggerIO* pScreen )
{
  static HugeStaticString panic_output;
  panic_output.clear();

  panic_output.append( "PANIC: " );
  panic_output.append( msg );

  // write the final string to the screen
  pScreen->drawString( panic_output, 0, 0, DebuggerIO::Red, DebuggerIO::Black );

  size_t nLines = newlineCount(panic_output) + 2;

  Log &log = Log::instance();
  Log::SeverityLevel level;
  static NormalStaticString Line;

  size_t iEntry = 0, iUsedEntries = 0;
  if ((pScreen->getHeight() - nLines) < (log.getStaticEntryCount() + log.getDynamicEntryCount()))
    iEntry = log.getStaticEntryCount() + log.getDynamicEntryCount() - (pScreen->getHeight() - nLines) + 1;
  bool bPrintThisLine = false;
  for( ; iEntry < (log.getStaticEntryCount() + log.getDynamicEntryCount()); iEntry++ )
  {
    if( iEntry < log.getStaticEntryCount() )
    {
      const Log::StaticLogEntry &entry = log.getStaticEntry(iEntry);
      level = entry.type;

//      if( level == Log::Fatal || level == Log::Error )
//      {
        Line.clear();
        Line.append("[");
        Line.append(entry.timestamp, 10, 8, '0');
        Line.append("] ");
        Line.append(entry.str);
        Line.append( "\n" );

        bPrintThisLine = true;
//      }
    }
    else
    {
      const Log::DynamicLogEntry &entry = log.getDynamicEntry(iEntry);
      level = entry.type;

//      if( level == Log::Fatal || level == Log::Error )
//      {
        Line.clear();
        Line.append("[");
        Line.append(entry.timestamp, 10, 8, '0');
        Line.append("] ");
        Line.append(entry.str);
        Line.append( "\n" );

        bPrintThisLine = true;
//      }
    }

    // print the line
    if( bPrintThisLine == true )
    {
      ++iUsedEntries;
      pScreen->drawString( Line, nLines + iUsedEntries, 0, DebuggerIO::White, DebuggerIO::Black );
      bPrintThisLine = false;
    }
  }
}

void panic( const char* msg )
{
  // Drop out of whatever graphics mode we were in
  GraphicsService::GraphicsProvider provider;
  memset(&provider, 0, sizeof(provider));
  provider.bTextModes = true;

  ServiceFeatures *pFeatures = ServiceManager::instance().enumerateOperations(String("graphics"));
  Service         *pService  = ServiceManager::instance().getService(String("graphics"));
  bool bSuccess = false;
  if(pFeatures->provides(ServiceFeatures::probe))
    if(pService)
      bSuccess = pService->serve(ServiceFeatures::probe, reinterpret_cast<void*>(&provider), sizeof(provider));

  if(bSuccess && !provider.bTextModes)
    provider.pDisplay->setScreenMode(0);

#ifdef MULTIPROCESSOR
  Machine::instance().stopAllOtherProcessors();
#endif

  /*
   * I/O implementations.
   */
  SerialIO serialIO(Machine::instance().getSerial(0));

  DebuggerIO *pInterfaces[2] = {0};

  int nInterfaces = 0;
  if(Machine::instance().getNumVga()) // Not all machines have "VGA", so handle that
  {
    static LocalIO localIO(Machine::instance().getVga(0), Machine::instance().getKeyboard());
#ifdef DONT_LOG_TO_SERIAL
    pInterfaces[0] = &localIO;
    nInterfaces = 1;
#else
    pInterfaces[0] = &localIO;
    pInterfaces[1] = &serialIO;
    nInterfaces = 2;
#endif
  }
#ifndef DONT_LOG_TO_SERIAL
  else
  {
    pInterfaces[0] = &serialIO;
    nInterfaces = 1;
  }
#endif

  for( int nIFace = 0; nIFace < nInterfaces; nIFace++ )
    _panic( msg, pInterfaces[nIFace] );

  // Halt the processor
  Processor::halt();
}
<commit_msg>kernel: fix panic() so it doesn't break halt() due to an interrupt arriving and return.<commit_after>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <Debugger.h>

#include <DebuggerIO.h>
#include <LocalIO.h>
#include <SerialIO.h>

#include <utilities/StaticString.h>

#include <processor/Processor.h>
#include <machine/Machine.h>

#include <Log.h>
#include <utilities/utility.h>

#include <graphics/GraphicsService.h>

static size_t newlineCount(const char *pString)
{
  size_t nNewlines = 0;
  while (*pString != '\0')
    if (*pString++ == '\n')
      ++nNewlines;

  return nNewlines;
}

// TODO: We might want a separate parameter for a stacktrace/register dump
void _panic( const char* msg, DebuggerIO* pScreen )
{
  static HugeStaticString panic_output;
  panic_output.clear();

  panic_output.append( "PANIC: " );
  panic_output.append( msg );

  // write the final string to the screen
  pScreen->drawString( panic_output, 0, 0, DebuggerIO::Red, DebuggerIO::Black );

  size_t nLines = newlineCount(panic_output) + 2;

  Log &log = Log::instance();
  Log::SeverityLevel level;
  static NormalStaticString Line;

  size_t iEntry = 0, iUsedEntries = 0;
  if ((pScreen->getHeight() - nLines) < (log.getStaticEntryCount() + log.getDynamicEntryCount()))
    iEntry = log.getStaticEntryCount() + log.getDynamicEntryCount() - (pScreen->getHeight() - nLines) + 1;
  bool bPrintThisLine = false;
  for( ; iEntry < (log.getStaticEntryCount() + log.getDynamicEntryCount()); iEntry++ )
  {
    if( iEntry < log.getStaticEntryCount() )
    {
      const Log::StaticLogEntry &entry = log.getStaticEntry(iEntry);
      level = entry.type;

//      if( level == Log::Fatal || level == Log::Error )
//      {
        Line.clear();
        Line.append("[");
        Line.append(entry.timestamp, 10, 8, '0');
        Line.append("] ");
        Line.append(entry.str);
        Line.append( "\n" );

        bPrintThisLine = true;
//      }
    }
    else
    {
      const Log::DynamicLogEntry &entry = log.getDynamicEntry(iEntry);
      level = entry.type;

//      if( level == Log::Fatal || level == Log::Error )
//      {
        Line.clear();
        Line.append("[");
        Line.append(entry.timestamp, 10, 8, '0');
        Line.append("] ");
        Line.append(entry.str);
        Line.append( "\n" );

        bPrintThisLine = true;
//      }
    }

    // print the line
    if( bPrintThisLine == true )
    {
      ++iUsedEntries;
      pScreen->drawString( Line, nLines + iUsedEntries, 0, DebuggerIO::White, DebuggerIO::Black );
      bPrintThisLine = false;
    }
  }
}

void panic( const char* msg )
{
  Processor::setInterrupts(false);

  // Drop out of whatever graphics mode we were in
  GraphicsService::GraphicsProvider provider;
  memset(&provider, 0, sizeof(provider));
  provider.bTextModes = true;

  ServiceFeatures *pFeatures = ServiceManager::instance().enumerateOperations(String("graphics"));
  Service         *pService  = ServiceManager::instance().getService(String("graphics"));
  bool bSuccess = false;
  if(pFeatures->provides(ServiceFeatures::probe))
    if(pService)
      bSuccess = pService->serve(ServiceFeatures::probe, reinterpret_cast<void*>(&provider), sizeof(provider));

  if(bSuccess && !provider.bTextModes)
    provider.pDisplay->setScreenMode(0);

#ifdef MULTIPROCESSOR
  Machine::instance().stopAllOtherProcessors();
#endif

  /*
   * I/O implementations.
   */
  SerialIO serialIO(Machine::instance().getSerial(0));

  DebuggerIO *pInterfaces[2] = {0};

  int nInterfaces = 0;
  if(Machine::instance().getNumVga()) // Not all machines have "VGA", so handle that
  {
    static LocalIO localIO(Machine::instance().getVga(0), Machine::instance().getKeyboard());
#ifdef DONT_LOG_TO_SERIAL
    pInterfaces[0] = &localIO;
    nInterfaces = 1;
#else
    pInterfaces[0] = &localIO;
    pInterfaces[1] = &serialIO;
    nInterfaces = 2;
#endif
  }
#ifndef DONT_LOG_TO_SERIAL
  else
  {
    pInterfaces[0] = &serialIO;
    nInterfaces = 1;
  }
#endif

  for( int nIFace = 0; nIFace < nInterfaces; nIFace++ )
    _panic( msg, pInterfaces[nIFace] );

  // Halt the processor
  while(1)
    Processor::halt();
}
<|endoftext|>


<commit_before><commit_msg>:( didnt include it in last commit<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2011 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/system_key_event_listener.h"

// TODO(saintlou): should we handle this define in gyp even if only used once?
#define XK_MISCELLANY 1
#include <X11/keysymdef.h>
#include <X11/XF86keysym.h>
#include <X11/XKBlib.h>

#include "chrome/browser/accessibility_events.h"
#include "chrome/browser/chromeos/audio_handler.h"
#include "chrome/browser/chromeos/brightness_bubble.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/dbus/power_manager_client.h"
#include "chrome/browser/chromeos/input_method/hotkey_manager.h"
#include "chrome/browser/chromeos/input_method/input_method_manager.h"
#include "chrome/browser/chromeos/input_method/xkeyboard.h"
#include "chrome/browser/chromeos/volume_bubble.h"
#include "content/browser/user_metrics.h"
#include "third_party/cros_system_api/window_manager/chromeos_wm_ipc_enums.h"
#include "ui/base/x/x11_util.h"

#if defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)
#include "base/message_pump_x.h"
#endif

namespace chromeos {

namespace {

// Percent by which the volume should be changed when a volume key is pressed.
const double kStepPercentage = 4.0;

// Percent to which the volume should be set when the "volume up" key is pressed
// while we're muted and have the volume set to 0.  See
// http://crosbug.com/13618.
const double kVolumePercentOnVolumeUpWhileMuted = 25.0;

static SystemKeyEventListener* g_system_key_event_listener = NULL;

}  // namespace

// static
void SystemKeyEventListener::Initialize() {
  CHECK(!g_system_key_event_listener);
  g_system_key_event_listener = new SystemKeyEventListener();
}

// static
void SystemKeyEventListener::Shutdown() {
  // We may call Shutdown without calling Initialize, e.g. if we exit early.
  if (g_system_key_event_listener) {
    delete g_system_key_event_listener;
    g_system_key_event_listener = NULL;
  }
}

// static
SystemKeyEventListener* SystemKeyEventListener::GetInstance() {
  VLOG_IF(1, !g_system_key_event_listener)
      << "SystemKeyEventListener::GetInstance() with NULL global instance.";
  return g_system_key_event_listener;
}

SystemKeyEventListener::SystemKeyEventListener()
    : stopped_(false),
      caps_lock_is_on_(input_method::XKeyboard::CapsLockIsEnabled()),
      xkb_event_base_(0) {
  Display* display = ui::GetXDisplay();
  key_brightness_down_ = XKeysymToKeycode(display,
                                          XF86XK_MonBrightnessDown);
  key_brightness_up_ = XKeysymToKeycode(display, XF86XK_MonBrightnessUp);
  key_volume_mute_ = XKeysymToKeycode(display, XF86XK_AudioMute);
  key_volume_down_ = XKeysymToKeycode(display, XF86XK_AudioLowerVolume);
  key_volume_up_ = XKeysymToKeycode(display, XF86XK_AudioRaiseVolume);
  key_f6_ = XKeysymToKeycode(display, XK_F6);
  key_f7_ = XKeysymToKeycode(display, XK_F7);
  key_f8_ = XKeysymToKeycode(display, XK_F8);
  key_f9_ = XKeysymToKeycode(display, XK_F9);
  key_f10_ = XKeysymToKeycode(display, XK_F10);
  key_left_shift_ = XKeysymToKeycode(display, XK_Shift_L);
  key_right_shift_ = XKeysymToKeycode(display, XK_Shift_R);

  if (key_brightness_down_)
    GrabKey(key_brightness_down_, 0);
  if (key_brightness_up_)
    GrabKey(key_brightness_up_, 0);
  if (key_volume_mute_)
    GrabKey(key_volume_mute_, 0);
  if (key_volume_down_)
    GrabKey(key_volume_down_, 0);
  if (key_volume_up_)
    GrabKey(key_volume_up_, 0);
  GrabKey(key_f6_, 0);
  GrabKey(key_f7_, 0);
  GrabKey(key_f8_, 0);
  GrabKey(key_f9_, 0);
  GrabKey(key_f10_, 0);

  int xkb_major_version = XkbMajorVersion;
  int xkb_minor_version = XkbMinorVersion;
  if (!XkbQueryExtension(display,
                         NULL,  // opcode_return
                         &xkb_event_base_,
                         NULL,  // error_return
                         &xkb_major_version,
                         &xkb_minor_version)) {
    LOG(WARNING) << "Could not query Xkb extension";
  }

  if (!XkbSelectEvents(display, XkbUseCoreKbd,
                       XkbStateNotifyMask,
                       XkbStateNotifyMask)) {
    LOG(WARNING) << "Could not install Xkb Indicator observer";
  }

#if defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)
  MessageLoopForUI::current()->AddObserver(this);
#else
  gdk_window_add_filter(NULL, GdkEventFilter, this);
#endif
}

SystemKeyEventListener::~SystemKeyEventListener() {
  Stop();
}

void SystemKeyEventListener::Stop() {
  if (stopped_)
    return;
#if defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)
  MessageLoopForUI::current()->RemoveObserver(this);
#else
  gdk_window_remove_filter(NULL, GdkEventFilter, this);
#endif
  stopped_ = true;
}

AudioHandler* SystemKeyEventListener::GetAudioHandler() const {
  AudioHandler* audio_handler = AudioHandler::GetInstance();
  if (!audio_handler || !audio_handler->IsInitialized())
    return NULL;
  return audio_handler;
}

void SystemKeyEventListener::AddCapsLockObserver(CapsLockObserver* observer) {
  caps_lock_observers_.AddObserver(observer);
}

void SystemKeyEventListener::RemoveCapsLockObserver(
    CapsLockObserver* observer) {
  caps_lock_observers_.RemoveObserver(observer);
}

#if defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)
base::EventStatus SystemKeyEventListener::WillProcessEvent(
    const base::NativeEvent& event) {
  return ProcessedXEvent(event) ? base::EVENT_HANDLED : base::EVENT_CONTINUE;
}

void SystemKeyEventListener::DidProcessEvent(const base::NativeEvent& event) {
}
#else  // defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)
// static
GdkFilterReturn SystemKeyEventListener::GdkEventFilter(GdkXEvent* gxevent,
                                                       GdkEvent* gevent,
                                                       gpointer data) {
  SystemKeyEventListener* listener = static_cast<SystemKeyEventListener*>(data);
  XEvent* xevent = static_cast<XEvent*>(gxevent);

  return listener->ProcessedXEvent(xevent) ? GDK_FILTER_REMOVE
                                           : GDK_FILTER_CONTINUE;
}
#endif  // defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)

void SystemKeyEventListener::GrabKey(int32 key, uint32 mask) {
  uint32 num_lock_mask = Mod2Mask;
  uint32 caps_lock_mask = LockMask;
  Display* display = ui::GetXDisplay();
  Window root = DefaultRootWindow(display);
  XGrabKey(display, key, mask, root, True, GrabModeAsync, GrabModeAsync);
  XGrabKey(display, key, mask | caps_lock_mask, root, True,
           GrabModeAsync, GrabModeAsync);
  XGrabKey(display, key, mask | num_lock_mask, root, True,
           GrabModeAsync, GrabModeAsync);
  XGrabKey(display, key, mask | caps_lock_mask | num_lock_mask, root,
           True, GrabModeAsync, GrabModeAsync);
}

void SystemKeyEventListener::OnBrightnessDown() {
  DBusThreadManager::Get()->power_manager_client()->
      DecreaseScreenBrightness(true);
}

void SystemKeyEventListener::OnBrightnessUp() {
  DBusThreadManager::Get()->power_manager_client()->
      IncreaseScreenBrightness();
}

void SystemKeyEventListener::OnVolumeMute() {
  AudioHandler* audio_handler = GetAudioHandler();
  if (!audio_handler)
    return;

  // Always muting (and not toggling) as per final decision on
  // http://crosbug.com/3751
  audio_handler->SetMuted(true);

  SendAccessibilityVolumeNotification(
      audio_handler->GetVolumePercent(),
      audio_handler->IsMuted());

  ShowVolumeBubble();
}

void SystemKeyEventListener::OnVolumeDown() {
  AudioHandler* audio_handler = GetAudioHandler();
  if (!audio_handler)
    return;

  if (audio_handler->IsMuted())
    audio_handler->SetVolumePercent(0.0);
  else
    audio_handler->AdjustVolumeByPercent(-kStepPercentage);

  SendAccessibilityVolumeNotification(
      audio_handler->GetVolumePercent(),
      audio_handler->IsMuted());

  ShowVolumeBubble();
}

void SystemKeyEventListener::OnVolumeUp() {
  AudioHandler* audio_handler = GetAudioHandler();
  if (!audio_handler)
    return;

  if (audio_handler->IsMuted()) {
    audio_handler->SetMuted(false);
    if (audio_handler->GetVolumePercent() <= 0.1)  // float comparison
      audio_handler->SetVolumePercent(kVolumePercentOnVolumeUpWhileMuted);
  } else {
    audio_handler->AdjustVolumeByPercent(kStepPercentage);
  }

  SendAccessibilityVolumeNotification(
      audio_handler->GetVolumePercent(),
      audio_handler->IsMuted());

  ShowVolumeBubble();
}

void SystemKeyEventListener::OnCapsLock(bool enabled) {
  FOR_EACH_OBSERVER(
      CapsLockObserver, caps_lock_observers_, OnCapsLockChange(enabled));
}

void SystemKeyEventListener::ShowVolumeBubble() {
  AudioHandler* audio_handler = GetAudioHandler();
  if (audio_handler) {
    VolumeBubble::GetInstance()->ShowBubble(
        audio_handler->GetVolumePercent(),
        !audio_handler->IsMuted());
  }
  BrightnessBubble::GetInstance()->HideBubble();
}

bool SystemKeyEventListener::ProcessedXEvent(XEvent* xevent) {
  if (xevent->type == KeyPress || xevent->type == KeyRelease) {
    // Change the current keyboard layout (or input method) if xevent is one of
    // the input method hotkeys.
    input_method::HotkeyManager* hotkey_manager =
        input_method::InputMethodManager::GetInstance()->GetHotkeyManager();
    if (hotkey_manager->FilterKeyEvent(*xevent)) {
      return true;
    }
  }

  if (xevent->type == xkb_event_base_) {
    XkbEvent* xkey_event = reinterpret_cast<XkbEvent*>(xevent);
    if (xkey_event->any.xkb_type == XkbStateNotify) {
      caps_lock_is_on_ = (xkey_event->state.locked_mods) & LockMask;
      OnCapsLock(caps_lock_is_on_);
      return true;
    }
  } else if (xevent->type == KeyPress) {
    const int32 keycode = xevent->xkey.keycode;
    if (keycode) {
      // Toggle Caps Lock if both Shift keys are pressed simultaneously.
      if (keycode == key_left_shift_ || keycode == key_right_shift_) {
        const bool other_shift_is_held = (xevent->xkey.state & ShiftMask);
        const bool other_mods_are_held =
            (xevent->xkey.state & ~(ShiftMask | LockMask));
        if (other_shift_is_held && !other_mods_are_held)
          input_method::XKeyboard::SetCapsLockEnabled(!caps_lock_is_on_);
      }

      // Only doing non-Alt/Shift/Ctrl modified keys
      if (!(xevent->xkey.state & (Mod1Mask | ShiftMask | ControlMask))) {
        if (keycode == key_f6_ || keycode == key_brightness_down_) {
          if (keycode == key_f6_)
            UserMetrics::RecordAction(
                UserMetricsAction("Accel_BrightnessDown_F6"));
          OnBrightnessDown();
          return true;
        } else if (keycode == key_f7_ || keycode == key_brightness_up_) {
          if (keycode == key_f7_)
            UserMetrics::RecordAction(
                UserMetricsAction("Accel_BrightnessUp_F7"));
          OnBrightnessUp();
          return true;
        } else if (keycode == key_f8_ || keycode == key_volume_mute_) {
          if (keycode == key_f8_)
            UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeMute_F8"));
          OnVolumeMute();
          return true;
        } else if (keycode == key_f9_ || keycode == key_volume_down_) {
          if (keycode == key_f9_)
            UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeDown_F9"));
          OnVolumeDown();
          return true;
        } else if (keycode == key_f10_ || keycode == key_volume_up_) {
          if (keycode == key_f10_)
            UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeUp_F10"));
          OnVolumeUp();
          return true;
        }
      }
    }
  }
  return false;
}

}  // namespace chromeos
<commit_msg>Implement the final UI for the CAPS LOCK indicator (part 2 of 3)<commit_after>// Copyright (c) 2011 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/system_key_event_listener.h"

// TODO(saintlou): should we handle this define in gyp even if only used once?
#define XK_MISCELLANY 1
#include <X11/keysymdef.h>
#include <X11/XF86keysym.h>
#include <X11/XKBlib.h>

#include "chrome/browser/accessibility_events.h"
#include "chrome/browser/chromeos/audio_handler.h"
#include "chrome/browser/chromeos/brightness_bubble.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/dbus/power_manager_client.h"
#include "chrome/browser/chromeos/input_method/hotkey_manager.h"
#include "chrome/browser/chromeos/input_method/input_method_manager.h"
#include "chrome/browser/chromeos/input_method/xkeyboard.h"
#include "chrome/browser/chromeos/volume_bubble.h"
#include "content/browser/user_metrics.h"
#include "third_party/cros_system_api/window_manager/chromeos_wm_ipc_enums.h"
#include "ui/base/x/x11_util.h"

#if defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)
#include "base/message_pump_x.h"
#endif

namespace chromeos {

namespace {

// Percent by which the volume should be changed when a volume key is pressed.
const double kStepPercentage = 4.0;

// Percent to which the volume should be set when the "volume up" key is pressed
// while we're muted and have the volume set to 0.  See
// http://crosbug.com/13618.
const double kVolumePercentOnVolumeUpWhileMuted = 25.0;

static SystemKeyEventListener* g_system_key_event_listener = NULL;

}  // namespace

// static
void SystemKeyEventListener::Initialize() {
  CHECK(!g_system_key_event_listener);
  g_system_key_event_listener = new SystemKeyEventListener();
}

// static
void SystemKeyEventListener::Shutdown() {
  // We may call Shutdown without calling Initialize, e.g. if we exit early.
  if (g_system_key_event_listener) {
    delete g_system_key_event_listener;
    g_system_key_event_listener = NULL;
  }
}

// static
SystemKeyEventListener* SystemKeyEventListener::GetInstance() {
  VLOG_IF(1, !g_system_key_event_listener)
      << "SystemKeyEventListener::GetInstance() with NULL global instance.";
  return g_system_key_event_listener;
}

SystemKeyEventListener::SystemKeyEventListener()
    : stopped_(false),
      caps_lock_is_on_(input_method::XKeyboard::CapsLockIsEnabled()),
      xkb_event_base_(0) {
  Display* display = ui::GetXDisplay();
  key_brightness_down_ = XKeysymToKeycode(display,
                                          XF86XK_MonBrightnessDown);
  key_brightness_up_ = XKeysymToKeycode(display, XF86XK_MonBrightnessUp);
  key_volume_mute_ = XKeysymToKeycode(display, XF86XK_AudioMute);
  key_volume_down_ = XKeysymToKeycode(display, XF86XK_AudioLowerVolume);
  key_volume_up_ = XKeysymToKeycode(display, XF86XK_AudioRaiseVolume);
  key_f6_ = XKeysymToKeycode(display, XK_F6);
  key_f7_ = XKeysymToKeycode(display, XK_F7);
  key_f8_ = XKeysymToKeycode(display, XK_F8);
  key_f9_ = XKeysymToKeycode(display, XK_F9);
  key_f10_ = XKeysymToKeycode(display, XK_F10);
  key_left_shift_ = XKeysymToKeycode(display, XK_Shift_L);
  key_right_shift_ = XKeysymToKeycode(display, XK_Shift_R);

  if (key_brightness_down_)
    GrabKey(key_brightness_down_, 0);
  if (key_brightness_up_)
    GrabKey(key_brightness_up_, 0);
  if (key_volume_mute_)
    GrabKey(key_volume_mute_, 0);
  if (key_volume_down_)
    GrabKey(key_volume_down_, 0);
  if (key_volume_up_)
    GrabKey(key_volume_up_, 0);
  GrabKey(key_f6_, 0);
  GrabKey(key_f7_, 0);
  GrabKey(key_f8_, 0);
  GrabKey(key_f9_, 0);
  GrabKey(key_f10_, 0);

  int xkb_major_version = XkbMajorVersion;
  int xkb_minor_version = XkbMinorVersion;
  if (!XkbQueryExtension(display,
                         NULL,  // opcode_return
                         &xkb_event_base_,
                         NULL,  // error_return
                         &xkb_major_version,
                         &xkb_minor_version)) {
    LOG(WARNING) << "Could not query Xkb extension";
  }

  if (!XkbSelectEvents(display, XkbUseCoreKbd,
                       XkbStateNotifyMask,
                       XkbStateNotifyMask)) {
    LOG(WARNING) << "Could not install Xkb Indicator observer";
  }

#if defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)
  MessageLoopForUI::current()->AddObserver(this);
#else
  gdk_window_add_filter(NULL, GdkEventFilter, this);
#endif
}

SystemKeyEventListener::~SystemKeyEventListener() {
  Stop();
}

void SystemKeyEventListener::Stop() {
  if (stopped_)
    return;
#if defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)
  MessageLoopForUI::current()->RemoveObserver(this);
#else
  gdk_window_remove_filter(NULL, GdkEventFilter, this);
#endif
  stopped_ = true;
}

AudioHandler* SystemKeyEventListener::GetAudioHandler() const {
  AudioHandler* audio_handler = AudioHandler::GetInstance();
  if (!audio_handler || !audio_handler->IsInitialized())
    return NULL;
  return audio_handler;
}

void SystemKeyEventListener::AddCapsLockObserver(CapsLockObserver* observer) {
  caps_lock_observers_.AddObserver(observer);
}

void SystemKeyEventListener::RemoveCapsLockObserver(
    CapsLockObserver* observer) {
  caps_lock_observers_.RemoveObserver(observer);
}

#if defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)
base::EventStatus SystemKeyEventListener::WillProcessEvent(
    const base::NativeEvent& event) {
  return ProcessedXEvent(event) ? base::EVENT_HANDLED : base::EVENT_CONTINUE;
}

void SystemKeyEventListener::DidProcessEvent(const base::NativeEvent& event) {
}
#else  // defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)
// static
GdkFilterReturn SystemKeyEventListener::GdkEventFilter(GdkXEvent* gxevent,
                                                       GdkEvent* gevent,
                                                       gpointer data) {
  SystemKeyEventListener* listener = static_cast<SystemKeyEventListener*>(data);
  XEvent* xevent = static_cast<XEvent*>(gxevent);

  return listener->ProcessedXEvent(xevent) ? GDK_FILTER_REMOVE
                                           : GDK_FILTER_CONTINUE;
}
#endif  // defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)

void SystemKeyEventListener::GrabKey(int32 key, uint32 mask) {
  uint32 num_lock_mask = Mod2Mask;
  uint32 caps_lock_mask = LockMask;
  Display* display = ui::GetXDisplay();
  Window root = DefaultRootWindow(display);
  XGrabKey(display, key, mask, root, True, GrabModeAsync, GrabModeAsync);
  XGrabKey(display, key, mask | caps_lock_mask, root, True,
           GrabModeAsync, GrabModeAsync);
  XGrabKey(display, key, mask | num_lock_mask, root, True,
           GrabModeAsync, GrabModeAsync);
  XGrabKey(display, key, mask | caps_lock_mask | num_lock_mask, root,
           True, GrabModeAsync, GrabModeAsync);
}

void SystemKeyEventListener::OnBrightnessDown() {
  DBusThreadManager::Get()->power_manager_client()->
      DecreaseScreenBrightness(true);
}

void SystemKeyEventListener::OnBrightnessUp() {
  DBusThreadManager::Get()->power_manager_client()->
      IncreaseScreenBrightness();
}

void SystemKeyEventListener::OnVolumeMute() {
  AudioHandler* audio_handler = GetAudioHandler();
  if (!audio_handler)
    return;

  // Always muting (and not toggling) as per final decision on
  // http://crosbug.com/3751
  audio_handler->SetMuted(true);

  SendAccessibilityVolumeNotification(
      audio_handler->GetVolumePercent(),
      audio_handler->IsMuted());

  ShowVolumeBubble();
}

void SystemKeyEventListener::OnVolumeDown() {
  AudioHandler* audio_handler = GetAudioHandler();
  if (!audio_handler)
    return;

  if (audio_handler->IsMuted())
    audio_handler->SetVolumePercent(0.0);
  else
    audio_handler->AdjustVolumeByPercent(-kStepPercentage);

  SendAccessibilityVolumeNotification(
      audio_handler->GetVolumePercent(),
      audio_handler->IsMuted());

  ShowVolumeBubble();
}

void SystemKeyEventListener::OnVolumeUp() {
  AudioHandler* audio_handler = GetAudioHandler();
  if (!audio_handler)
    return;

  if (audio_handler->IsMuted()) {
    audio_handler->SetMuted(false);
    if (audio_handler->GetVolumePercent() <= 0.1)  // float comparison
      audio_handler->SetVolumePercent(kVolumePercentOnVolumeUpWhileMuted);
  } else {
    audio_handler->AdjustVolumeByPercent(kStepPercentage);
  }

  SendAccessibilityVolumeNotification(
      audio_handler->GetVolumePercent(),
      audio_handler->IsMuted());

  ShowVolumeBubble();
}

void SystemKeyEventListener::OnCapsLock(bool enabled) {
  FOR_EACH_OBSERVER(
      CapsLockObserver, caps_lock_observers_, OnCapsLockChange(enabled));
}

void SystemKeyEventListener::ShowVolumeBubble() {
  AudioHandler* audio_handler = GetAudioHandler();
  if (audio_handler) {
    VolumeBubble::GetInstance()->ShowBubble(
        audio_handler->GetVolumePercent(),
        !audio_handler->IsMuted());
  }
  BrightnessBubble::GetInstance()->HideBubble();
}

bool SystemKeyEventListener::ProcessedXEvent(XEvent* xevent) {
  if (xevent->type == KeyPress || xevent->type == KeyRelease) {
    // Change the current keyboard layout (or input method) if xevent is one of
    // the input method hotkeys.
    input_method::HotkeyManager* hotkey_manager =
        input_method::InputMethodManager::GetInstance()->GetHotkeyManager();
    if (hotkey_manager->FilterKeyEvent(*xevent)) {
      return true;
    }
  }

  if (xevent->type == xkb_event_base_) {
    XkbEvent* xkey_event = reinterpret_cast<XkbEvent*>(xevent);
    if (xkey_event->any.xkb_type == XkbStateNotify) {
      const bool new_lock_state = (xkey_event->state.locked_mods) & LockMask;
      if (caps_lock_is_on_ != new_lock_state) {
        caps_lock_is_on_ = new_lock_state;
        OnCapsLock(caps_lock_is_on_);
      }
      return true;
    }
  } else if (xevent->type == KeyPress) {
    const int32 keycode = xevent->xkey.keycode;
    if (keycode) {
      // Toggle Caps Lock if both Shift keys are pressed simultaneously.
      if (keycode == key_left_shift_ || keycode == key_right_shift_) {
        const bool other_shift_is_held = (xevent->xkey.state & ShiftMask);
        const bool other_mods_are_held =
            (xevent->xkey.state & ~(ShiftMask | LockMask));
        if (other_shift_is_held && !other_mods_are_held)
          input_method::XKeyboard::SetCapsLockEnabled(!caps_lock_is_on_);
      }

      // Only doing non-Alt/Shift/Ctrl modified keys
      if (!(xevent->xkey.state & (Mod1Mask | ShiftMask | ControlMask))) {
        if (keycode == key_f6_ || keycode == key_brightness_down_) {
          if (keycode == key_f6_)
            UserMetrics::RecordAction(
                UserMetricsAction("Accel_BrightnessDown_F6"));
          OnBrightnessDown();
          return true;
        } else if (keycode == key_f7_ || keycode == key_brightness_up_) {
          if (keycode == key_f7_)
            UserMetrics::RecordAction(
                UserMetricsAction("Accel_BrightnessUp_F7"));
          OnBrightnessUp();
          return true;
        } else if (keycode == key_f8_ || keycode == key_volume_mute_) {
          if (keycode == key_f8_)
            UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeMute_F8"));
          OnVolumeMute();
          return true;
        } else if (keycode == key_f9_ || keycode == key_volume_down_) {
          if (keycode == key_f9_)
            UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeDown_F9"));
          OnVolumeDown();
          return true;
        } else if (keycode == key_f10_ || keycode == key_volume_up_) {
          if (keycode == key_f10_)
            UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeUp_F10"));
          OnVolumeUp();
          return true;
        }
      }
    }
  }
  return false;
}

}  // 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/gtk/clear_browsing_data_dialog_gtk.h"

#include <string>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browsing_data_remover.h"
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"

namespace {

// Returns true if the checkbox is checked.
gboolean IsChecked(GtkWidget* widget) {
  return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}

}  // namespace

// static
void ClearBrowsingDataDialogGtk::Show(GtkWindow* parent, Profile* profile) {
  new ClearBrowsingDataDialogGtk(parent, profile);
}

ClearBrowsingDataDialogGtk::ClearBrowsingDataDialogGtk(GtkWindow* parent,
                                                       Profile* profile) :
    profile_(profile), remover_(NULL) {
  // Build the dialog.
  std::string dialog_name = l10n_util::GetStringUTF8(
      IDS_CLEAR_BROWSING_DATA_TITLE);
  dialog_ = gtk_dialog_new_with_buttons(
      dialog_name.c_str(),
      parent,
      (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
      GTK_STOCK_CLOSE,
      GTK_RESPONSE_REJECT,
      NULL);

  accessible_widget_helper_.reset(new AccessibleWidgetHelper(dialog_, profile));
  accessible_widget_helper_->SendOpenWindowNotification(dialog_name);

  gtk_util::AddButtonToDialog(dialog_,
      l10n_util::GetStringUTF8(IDS_CLEAR_BROWSING_DATA_COMMIT).c_str(),
      GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT);

  GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox;
  gtk_box_set_spacing(GTK_BOX(content_area), gtk_util::kContentAreaSpacing);

  GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
  gtk_container_add(GTK_CONTAINER(content_area), vbox);

  // Label on top of the checkboxes.
  GtkWidget* description = gtk_label_new(
      l10n_util::GetStringUTF8(IDS_CLEAR_BROWSING_DATA_LABEL).c_str());
  gtk_misc_set_alignment(GTK_MISC(description), 0, 0);
  gtk_box_pack_start(GTK_BOX(vbox), description, FALSE, FALSE, 0);

  // History checkbox.
  del_history_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_BROWSING_HISTORY_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_history_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_history_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeleteBrowsingHistory));
  g_signal_connect(del_history_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Downloads checkbox.
  del_downloads_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_DOWNLOAD_HISTORY_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_downloads_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_downloads_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeleteDownloadHistory));
  g_signal_connect(del_downloads_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Cache checkbox.
  del_cache_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_CACHE_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_cache_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_cache_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeleteCache));
  g_signal_connect(del_cache_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Cookies checkbox.
  del_cookies_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_COOKIES_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_cookies_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_cookies_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeleteCookies));
  g_signal_connect(del_cookies_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Passwords checkbox.
  del_passwords_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_PASSWORDS_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_passwords_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_passwords_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeletePasswords));
  g_signal_connect(del_passwords_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Form data checkbox.
  del_form_data_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_FORM_DATA_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_form_data_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_form_data_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeleteFormData));
  g_signal_connect(del_form_data_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Create a horizontal layout for the combo box and label.
  GtkWidget* combo_hbox = gtk_hbox_new(FALSE, gtk_util::kLabelSpacing);
  GtkWidget* time_period_label_ = gtk_label_new(
      l10n_util::GetStringUTF8(IDS_CLEAR_BROWSING_DATA_TIME_LABEL).c_str());
  gtk_box_pack_start(GTK_BOX(combo_hbox), time_period_label_, FALSE, FALSE, 0);

  // Time period combo box items.
  time_period_combobox_ = gtk_combo_box_new_text();
  gtk_combo_box_append_text(GTK_COMBO_BOX(time_period_combobox_),
      l10n_util::GetStringUTF8(IDS_CLEAR_DATA_HOUR).c_str());
  gtk_combo_box_append_text(GTK_COMBO_BOX(time_period_combobox_),
      l10n_util::GetStringUTF8(IDS_CLEAR_DATA_DAY).c_str());
  gtk_combo_box_append_text(GTK_COMBO_BOX(time_period_combobox_),
      l10n_util::GetStringUTF8(IDS_CLEAR_DATA_WEEK).c_str());
  gtk_combo_box_append_text(GTK_COMBO_BOX(time_period_combobox_),
      l10n_util::GetStringUTF8(IDS_CLEAR_DATA_4WEEKS).c_str());
  gtk_combo_box_append_text(GTK_COMBO_BOX(time_period_combobox_),
      l10n_util::GetStringUTF8(IDS_CLEAR_DATA_EVERYTHING).c_str());
  gtk_combo_box_set_active(GTK_COMBO_BOX(time_period_combobox_),
      profile_->GetPrefs()->GetInteger(prefs::kDeleteTimePeriod));
  gtk_box_pack_start(GTK_BOX(combo_hbox),
                     time_period_combobox_, FALSE, FALSE, 0);
  g_signal_connect(time_period_combobox_, "changed",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Add the combo/label time period box to the vertical layout.
  gtk_box_pack_start(GTK_BOX(vbox), combo_hbox, FALSE, FALSE, 0);

  // Add widgets for the area below the accept buttons.
  GtkWidget* flash_link = gtk_chrome_link_button_new(
      l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_SETTINGS).c_str());
  g_signal_connect(G_OBJECT(flash_link), "clicked",
                   G_CALLBACK(OnFlashLinkClickedThunk), this);
  GtkWidget* flash_link_hbox = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(flash_link_hbox), flash_link, FALSE, FALSE, 0);
  gtk_box_pack_end(GTK_BOX(content_area), flash_link_hbox, FALSE, FALSE, 0);

  GtkWidget* separator = gtk_hseparator_new();
  gtk_box_pack_end(GTK_BOX(content_area), separator, FALSE, FALSE, 0);

  // Make sure we can move things around.
  DCHECK_EQ(GTK_DIALOG(dialog_)->action_area->parent, content_area);

  // Now rearrange those because they're *above* the accept buttons...there's
  // no way to place them in the correct position with gtk_box_pack_end() so
  // manually move things into the correct order.
  gtk_box_reorder_child(GTK_BOX(content_area), flash_link_hbox, -1);
  gtk_box_reorder_child(GTK_BOX(content_area), separator, -1);
  gtk_box_reorder_child(GTK_BOX(content_area), GTK_DIALOG(dialog_)->action_area,
                        -1);

  g_signal_connect(dialog_, "response",
                   G_CALLBACK(OnDialogResponseThunk), this);

  UpdateDialogButtons();

  gtk_util::ShowDialogWithLocalizedSize(dialog_,
                                        IDS_CLEARDATA_DIALOG_WIDTH_CHARS,
                                        -1,
                                        false);
}

ClearBrowsingDataDialogGtk::~ClearBrowsingDataDialogGtk() {
}

void ClearBrowsingDataDialogGtk::OnDialogResponse(GtkWidget* widget,
                                                  int response) {
  if (response == GTK_RESPONSE_ACCEPT) {
    int period_selected = gtk_combo_box_get_active(
        GTK_COMBO_BOX(time_period_combobox_));

    // BrowsingDataRemover deletes itself when done.
    remover_ = new BrowsingDataRemover(profile_,
        static_cast<BrowsingDataRemover::TimePeriod>(period_selected),
        base::Time());
    remover_->Remove(GetCheckedItems());
  }

  delete this;
  gtk_widget_destroy(GTK_WIDGET(widget));
}

void ClearBrowsingDataDialogGtk::OnDialogWidgetClicked(GtkWidget* widget) {
  if (widget == del_history_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeleteBrowsingHistory,
                                     IsChecked(widget));
  } else if (widget == del_downloads_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeleteDownloadHistory,
                                     IsChecked(widget));
  } else if (widget == del_cache_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeleteCache,
                                     IsChecked(widget));
  } else if (widget == del_cookies_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeleteCookies,
                                     IsChecked(widget));
  } else if (widget == del_passwords_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeletePasswords,
                                     IsChecked(widget));
  } else if (widget == del_form_data_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeleteFormData,
                                     IsChecked(widget));
  } else if (widget == time_period_combobox_) {
    profile_->GetPrefs()->SetInteger(prefs::kDeleteTimePeriod,
        gtk_combo_box_get_active(GTK_COMBO_BOX(widget)));
  }
  UpdateDialogButtons();
}

void ClearBrowsingDataDialogGtk::OnFlashLinkClicked(GtkWidget* button) {
  // We open a new browser window so the Options dialog doesn't get lost
  // behind other windows.
  Browser* browser = Browser::Create(profile_);
  browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_URL)),
                   GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
  browser->window()->Show();
}

void ClearBrowsingDataDialogGtk::UpdateDialogButtons() {
  gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT,
                                    GetCheckedItems() != 0);
}

int ClearBrowsingDataDialogGtk::GetCheckedItems() {
  int items = 0;
  if (IsChecked(del_history_checkbox_))
    items |= BrowsingDataRemover::REMOVE_HISTORY;
  if (IsChecked(del_downloads_checkbox_))
    items |= BrowsingDataRemover::REMOVE_DOWNLOADS;
  if (IsChecked(del_cookies_checkbox_))
    items |= BrowsingDataRemover::REMOVE_COOKIES;
  if (IsChecked(del_passwords_checkbox_))
    items |= BrowsingDataRemover::REMOVE_PASSWORDS;
  if (IsChecked(del_form_data_checkbox_))
    items |= BrowsingDataRemover::REMOVE_FORM_DATA;
  if (IsChecked(del_cache_checkbox_))
    items |= BrowsingDataRemover::REMOVE_CACHE;
  return items;
}
<commit_msg>Make "Clear Browser Data" dialog wider for ja.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/clear_browsing_data_dialog_gtk.h"

#include <string>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browsing_data_remover.h"
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"

namespace {

// Returns true if the checkbox is checked.
gboolean IsChecked(GtkWidget* widget) {
  return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}

}  // namespace

// static
void ClearBrowsingDataDialogGtk::Show(GtkWindow* parent, Profile* profile) {
  new ClearBrowsingDataDialogGtk(parent, profile);
}

ClearBrowsingDataDialogGtk::ClearBrowsingDataDialogGtk(GtkWindow* parent,
                                                       Profile* profile) :
    profile_(profile), remover_(NULL) {
  // Build the dialog.
  std::string dialog_name = l10n_util::GetStringUTF8(
      IDS_CLEAR_BROWSING_DATA_TITLE);
  dialog_ = gtk_dialog_new_with_buttons(
      dialog_name.c_str(),
      parent,
      (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
      GTK_STOCK_CLOSE,
      GTK_RESPONSE_REJECT,
      NULL);

  accessible_widget_helper_.reset(new AccessibleWidgetHelper(dialog_, profile));
  accessible_widget_helper_->SendOpenWindowNotification(dialog_name);

  gtk_util::AddButtonToDialog(dialog_,
      l10n_util::GetStringUTF8(IDS_CLEAR_BROWSING_DATA_COMMIT).c_str(),
      GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT);

  GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox;
  gtk_box_set_spacing(GTK_BOX(content_area), gtk_util::kContentAreaSpacing);

  GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
  gtk_container_add(GTK_CONTAINER(content_area), vbox);

  // Label on top of the checkboxes.
  GtkWidget* description = gtk_label_new(
      l10n_util::GetStringUTF8(IDS_CLEAR_BROWSING_DATA_LABEL).c_str());
  gtk_misc_set_alignment(GTK_MISC(description), 0, 0);
  gtk_box_pack_start(GTK_BOX(vbox), description, FALSE, FALSE, 0);

  // History checkbox.
  del_history_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_BROWSING_HISTORY_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_history_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_history_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeleteBrowsingHistory));
  g_signal_connect(del_history_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Downloads checkbox.
  del_downloads_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_DOWNLOAD_HISTORY_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_downloads_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_downloads_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeleteDownloadHistory));
  g_signal_connect(del_downloads_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Cache checkbox.
  del_cache_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_CACHE_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_cache_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_cache_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeleteCache));
  g_signal_connect(del_cache_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Cookies checkbox.
  del_cookies_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_COOKIES_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_cookies_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_cookies_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeleteCookies));
  g_signal_connect(del_cookies_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Passwords checkbox.
  del_passwords_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_PASSWORDS_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_passwords_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_passwords_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeletePasswords));
  g_signal_connect(del_passwords_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Form data checkbox.
  del_form_data_checkbox_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DEL_FORM_DATA_CHKBOX).c_str());
  gtk_box_pack_start(GTK_BOX(vbox), del_form_data_checkbox_, FALSE, FALSE, 0);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(del_form_data_checkbox_),
      profile_->GetPrefs()->GetBoolean(prefs::kDeleteFormData));
  g_signal_connect(del_form_data_checkbox_, "toggled",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Create a horizontal layout for the combo box and label.
  GtkWidget* combo_hbox = gtk_hbox_new(FALSE, gtk_util::kLabelSpacing);
  GtkWidget* time_period_label_ = gtk_label_new(
      l10n_util::GetStringUTF8(IDS_CLEAR_BROWSING_DATA_TIME_LABEL).c_str());
  gtk_box_pack_start(GTK_BOX(combo_hbox), time_period_label_, FALSE, FALSE, 0);

  // Time period combo box items.
  time_period_combobox_ = gtk_combo_box_new_text();
  gtk_combo_box_append_text(GTK_COMBO_BOX(time_period_combobox_),
      l10n_util::GetStringUTF8(IDS_CLEAR_DATA_HOUR).c_str());
  gtk_combo_box_append_text(GTK_COMBO_BOX(time_period_combobox_),
      l10n_util::GetStringUTF8(IDS_CLEAR_DATA_DAY).c_str());
  gtk_combo_box_append_text(GTK_COMBO_BOX(time_period_combobox_),
      l10n_util::GetStringUTF8(IDS_CLEAR_DATA_WEEK).c_str());
  gtk_combo_box_append_text(GTK_COMBO_BOX(time_period_combobox_),
      l10n_util::GetStringUTF8(IDS_CLEAR_DATA_4WEEKS).c_str());
  gtk_combo_box_append_text(GTK_COMBO_BOX(time_period_combobox_),
      l10n_util::GetStringUTF8(IDS_CLEAR_DATA_EVERYTHING).c_str());
  gtk_combo_box_set_active(GTK_COMBO_BOX(time_period_combobox_),
      profile_->GetPrefs()->GetInteger(prefs::kDeleteTimePeriod));
  gtk_box_pack_start(GTK_BOX(combo_hbox),
                     time_period_combobox_, FALSE, FALSE, 0);
  g_signal_connect(time_period_combobox_, "changed",
                   G_CALLBACK(OnDialogWidgetClickedThunk), this);

  // Add the combo/label time period box to the vertical layout.
  gtk_box_pack_start(GTK_BOX(vbox), combo_hbox, FALSE, FALSE, 0);

  // Add widgets for the area below the accept buttons.
  GtkWidget* flash_link = gtk_chrome_link_button_new(
      l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_SETTINGS).c_str());
  g_signal_connect(G_OBJECT(flash_link), "clicked",
                   G_CALLBACK(OnFlashLinkClickedThunk), this);
  GtkWidget* flash_link_hbox = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(flash_link_hbox), flash_link, FALSE, FALSE, 0);
  gtk_box_pack_end(GTK_BOX(content_area), flash_link_hbox, FALSE, FALSE, 0);

  GtkWidget* separator = gtk_hseparator_new();
  gtk_box_pack_end(GTK_BOX(content_area), separator, FALSE, FALSE, 0);

  // Make sure we can move things around.
  DCHECK_EQ(GTK_DIALOG(dialog_)->action_area->parent, content_area);

  // Now rearrange those because they're *above* the accept buttons...there's
  // no way to place them in the correct position with gtk_box_pack_end() so
  // manually move things into the correct order.
  gtk_box_reorder_child(GTK_BOX(content_area), flash_link_hbox, -1);
  gtk_box_reorder_child(GTK_BOX(content_area), separator, -1);
  gtk_box_reorder_child(GTK_BOX(content_area), GTK_DIALOG(dialog_)->action_area,
                        -1);

  g_signal_connect(dialog_, "response",
                   G_CALLBACK(OnDialogResponseThunk), this);

  UpdateDialogButtons();

  gtk_util::ShowModalDialogWithMinLocalizedWidth(dialog_,
      IDS_CLEARDATA_DIALOG_WIDTH_CHARS);
}

ClearBrowsingDataDialogGtk::~ClearBrowsingDataDialogGtk() {
}

void ClearBrowsingDataDialogGtk::OnDialogResponse(GtkWidget* widget,
                                                  int response) {
  if (response == GTK_RESPONSE_ACCEPT) {
    int period_selected = gtk_combo_box_get_active(
        GTK_COMBO_BOX(time_period_combobox_));

    // BrowsingDataRemover deletes itself when done.
    remover_ = new BrowsingDataRemover(profile_,
        static_cast<BrowsingDataRemover::TimePeriod>(period_selected),
        base::Time());
    remover_->Remove(GetCheckedItems());
  }

  delete this;
  gtk_widget_destroy(GTK_WIDGET(widget));
}

void ClearBrowsingDataDialogGtk::OnDialogWidgetClicked(GtkWidget* widget) {
  if (widget == del_history_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeleteBrowsingHistory,
                                     IsChecked(widget));
  } else if (widget == del_downloads_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeleteDownloadHistory,
                                     IsChecked(widget));
  } else if (widget == del_cache_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeleteCache,
                                     IsChecked(widget));
  } else if (widget == del_cookies_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeleteCookies,
                                     IsChecked(widget));
  } else if (widget == del_passwords_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeletePasswords,
                                     IsChecked(widget));
  } else if (widget == del_form_data_checkbox_) {
    profile_->GetPrefs()->SetBoolean(prefs::kDeleteFormData,
                                     IsChecked(widget));
  } else if (widget == time_period_combobox_) {
    profile_->GetPrefs()->SetInteger(prefs::kDeleteTimePeriod,
        gtk_combo_box_get_active(GTK_COMBO_BOX(widget)));
  }
  UpdateDialogButtons();
}

void ClearBrowsingDataDialogGtk::OnFlashLinkClicked(GtkWidget* button) {
  // We open a new browser window so the Options dialog doesn't get lost
  // behind other windows.
  Browser* browser = Browser::Create(profile_);
  browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_URL)),
                   GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
  browser->window()->Show();
}

void ClearBrowsingDataDialogGtk::UpdateDialogButtons() {
  gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT,
                                    GetCheckedItems() != 0);
}

int ClearBrowsingDataDialogGtk::GetCheckedItems() {
  int items = 0;
  if (IsChecked(del_history_checkbox_))
    items |= BrowsingDataRemover::REMOVE_HISTORY;
  if (IsChecked(del_downloads_checkbox_))
    items |= BrowsingDataRemover::REMOVE_DOWNLOADS;
  if (IsChecked(del_cookies_checkbox_))
    items |= BrowsingDataRemover::REMOVE_COOKIES;
  if (IsChecked(del_passwords_checkbox_))
    items |= BrowsingDataRemover::REMOVE_PASSWORDS;
  if (IsChecked(del_form_data_checkbox_))
    items |= BrowsingDataRemover::REMOVE_FORM_DATA;
  if (IsChecked(del_cache_checkbox_))
    items |= BrowsingDataRemover::REMOVE_CACHE;
  return items;
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-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/common/extensions/extension_error_reporter.h"

#include "build/build_config.h"

#if defined(OS_WIN)
#include "app/win_util.h"
#elif defined(OS_MACOSX)
#include "base/scoped_cftyperef.h"
#include "base/sys_string_conversions.h"
#include <CoreFoundation/CFUserNotification.h>
#endif
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"

// No AddRef required when using ExtensionErrorReporter with RunnableMethod.
// This is okay since the ExtensionErrorReporter is a singleton that lives until
// the end of the process.
template <> struct RunnableMethodTraits<ExtensionErrorReporter> {
  static void RetainCallee(ExtensionErrorReporter*) {}
  static void ReleaseCallee(ExtensionErrorReporter*) {}
};

ExtensionErrorReporter* ExtensionErrorReporter::instance_ = NULL;

// static
void ExtensionErrorReporter::Init(bool enable_noisy_errors) {
  if (!instance_) {
    instance_ = new ExtensionErrorReporter(enable_noisy_errors);
  }
}

// static
ExtensionErrorReporter* ExtensionErrorReporter::GetInstance() {
  CHECK(instance_) << "Init() was never called";
  return instance_;
}

ExtensionErrorReporter::ExtensionErrorReporter(bool enable_noisy_errors)
    : ui_loop_(MessageLoop::current()),
      enable_noisy_errors_(enable_noisy_errors) {
}

void ExtensionErrorReporter::ReportError(const std::string& message,
                                         bool be_noisy) {
  // NOTE: There won't be a ui_loop_ in the unit test environment.
  if (ui_loop_ && MessageLoop::current() != ui_loop_) {
    ui_loop_->PostTask(FROM_HERE,
        NewRunnableMethod(this, &ExtensionErrorReporter::ReportError, message,
                          be_noisy));
    return;
  }

  errors_.push_back(message);

  // TODO(aa): Print the error message out somewhere better. I think we are
  // going to need some sort of 'extension inspector'.
  LOG(WARNING) << message;

  if (enable_noisy_errors_ && be_noisy) {
#if defined(OS_WIN)
    win_util::MessageBox(NULL, UTF8ToWide(message), L"Extension error",
        MB_OK | MB_SETFOREGROUND);
#elif defined(OS_MACOSX)
    // There must be a better way to do this, for all platforms.
    scoped_cftyperef<CFStringRef> message_cf(
        base::SysUTF8ToCFStringRef(message));
    CFOptionFlags response;
    CFUserNotificationDisplayAlert(
        0, kCFUserNotificationCautionAlertLevel, NULL, NULL, NULL,
        CFSTR("Extension error"), message_cf,
        NULL, NULL, NULL, &response);
#else
    // TODO(port)
#endif
  }
}

const std::vector<std::string>* ExtensionErrorReporter::GetErrors() {
  return &errors_;
}

void ExtensionErrorReporter::ClearErrors() {
  errors_.clear();
}
<commit_msg>Increase the severity of the warning that is logged on extension load failure. This doesn't fix the bug, but might help with debugging until we have an alert box.<commit_after>// Copyright (c) 2006-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/common/extensions/extension_error_reporter.h"

#include "build/build_config.h"

#if defined(OS_WIN)
#include "app/win_util.h"
#elif defined(OS_MACOSX)
#include "base/scoped_cftyperef.h"
#include "base/sys_string_conversions.h"
#include <CoreFoundation/CFUserNotification.h>
#endif
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"

// No AddRef required when using ExtensionErrorReporter with RunnableMethod.
// This is okay since the ExtensionErrorReporter is a singleton that lives until
// the end of the process.
template <> struct RunnableMethodTraits<ExtensionErrorReporter> {
  static void RetainCallee(ExtensionErrorReporter*) {}
  static void ReleaseCallee(ExtensionErrorReporter*) {}
};

ExtensionErrorReporter* ExtensionErrorReporter::instance_ = NULL;

// static
void ExtensionErrorReporter::Init(bool enable_noisy_errors) {
  if (!instance_) {
    instance_ = new ExtensionErrorReporter(enable_noisy_errors);
  }
}

// static
ExtensionErrorReporter* ExtensionErrorReporter::GetInstance() {
  CHECK(instance_) << "Init() was never called";
  return instance_;
}

ExtensionErrorReporter::ExtensionErrorReporter(bool enable_noisy_errors)
    : ui_loop_(MessageLoop::current()),
      enable_noisy_errors_(enable_noisy_errors) {
}

void ExtensionErrorReporter::ReportError(const std::string& message,
                                         bool be_noisy) {
  // NOTE: There won't be a ui_loop_ in the unit test environment.
  if (ui_loop_ && MessageLoop::current() != ui_loop_) {
    ui_loop_->PostTask(FROM_HERE,
        NewRunnableMethod(this, &ExtensionErrorReporter::ReportError, message,
                          be_noisy));
    return;
  }

  errors_.push_back(message);

  // TODO(aa): Print the error message out somewhere better. I think we are
  // going to need some sort of 'extension inspector'.
  LOG(ERROR) << "Extension error: " << message;

  if (enable_noisy_errors_ && be_noisy) {
#if defined(OS_WIN)
    win_util::MessageBox(NULL, UTF8ToWide(message), L"Extension error",
        MB_OK | MB_SETFOREGROUND);
#elif defined(OS_MACOSX)
    // There must be a better way to do this, for all platforms.
    scoped_cftyperef<CFStringRef> message_cf(
        base::SysUTF8ToCFStringRef(message));
    CFOptionFlags response;
    CFUserNotificationDisplayAlert(
        0, kCFUserNotificationCautionAlertLevel, NULL, NULL, NULL,
        CFSTR("Extension error"), message_cf,
        NULL, NULL, NULL, &response);
#else
    // TODO(port)
#endif
  }
}

const std::vector<std::string>* ExtensionErrorReporter::GetErrors() {
  return &errors_;
}

void ExtensionErrorReporter::ClearErrors() {
  errors_.clear();
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2006 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

// Most of this was borrowed (with minor modifications) from V8's and Chromium's
// src/base/logging.cc.

#include <cstdarg>
#include <cstdio>
#include <cstdlib>

#if defined(WEBRTC_ANDROID)
#define RTC_LOG_TAG_ANDROID "rtc"
#include <android/log.h>  // NOLINT
#endif

#if defined(WEBRTC_WIN)
#include <windows.h>
#endif

#if defined(WEBRTC_WIN)
#define LAST_SYSTEM_ERROR (::GetLastError())
#elif defined(__native_client__) && __native_client__
#define LAST_SYSTEM_ERROR (0)
#elif defined(WEBRTC_POSIX)
#define LAST_SYSTEM_ERROR (errno)
#endif  // WEBRTC_WIN

#include "rtc_base/checks.h"

#if defined(_MSC_VER)
// Warning C4722: destructor never returns, potential memory leak.
// FatalMessage's dtor very intentionally aborts.
#pragma warning(disable:4722)
#endif

namespace rtc {
namespace {

void VPrintError(const char* format, va_list args) {
#if defined(WEBRTC_ANDROID)
  __android_log_vprint(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, format, args);
#else
  vfprintf(stderr, format, args);
#endif
}

#if defined(__GNUC__)
void PrintError(const char* format, ...)
    __attribute__((__format__(__printf__, 1, 2)));
#endif

void PrintError(const char* format, ...) {
  va_list args;
  va_start(args, format);
  VPrintError(format, args);
  va_end(args);
}

}  // namespace

FatalMessage::FatalMessage(const char* file, int line) {
  Init(file, line);
}

FatalMessage::FatalMessage(const char* file, int line, std::string* result) {
  Init(file, line);
  stream_ << "Check failed: " << *result << std::endl << "# ";
  delete result;
}

NO_RETURN FatalMessage::~FatalMessage() {
  fflush(stdout);
  fflush(stderr);
  stream_ << std::endl << "#" << std::endl;
  PrintError("%s", stream_.str().c_str());
  fflush(stderr);
  abort();
}

void FatalMessage::Init(const char* file, int line) {
  stream_ << std::endl
          << std::endl
          << "#" << std::endl
          << "# Fatal error in " << file << ", line " << line << std::endl
          << "# last system error: " << LAST_SYSTEM_ERROR << std::endl
          << "# ";
}

// MSVC doesn't like complex extern templates and DLLs.
#if !defined(COMPILER_MSVC)
// Explicit instantiations for commonly used comparisons.
template std::string* MakeCheckOpString<int, int>(
    const int&, const int&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned long>(
    const unsigned long&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned int>(
    const unsigned long&, const unsigned int&, const char* names);
template std::string* MakeCheckOpString<unsigned int, unsigned long>(
    const unsigned int&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<std::string, std::string>(
    const std::string&, const std::string&, const char* name);
#endif

}  // namespace rtc

// Function to call from the C version of the RTC_CHECK and RTC_DCHECK macros.
NO_RETURN void rtc_FatalMessage(const char* file, int line, const char* msg) {
  rtc::FatalMessage(file, line).stream() << msg;
}
<commit_msg>Add the missing header for `errno` variable in `checks.cc`<commit_after>/*
 *  Copyright 2006 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

// Most of this was borrowed (with minor modifications) from V8's and Chromium's
// src/base/logging.cc.

#include <cstdarg>
#include <cstdio>
#include <cstdlib>

#if defined(WEBRTC_ANDROID)
#define RTC_LOG_TAG_ANDROID "rtc"
#include <android/log.h>  // NOLINT
#endif

#if defined(WEBRTC_WIN)
#include <windows.h>
#endif

#if defined(WEBRTC_WIN)
#define LAST_SYSTEM_ERROR (::GetLastError())
#elif defined(__native_client__) && __native_client__
#define LAST_SYSTEM_ERROR (0)
#elif defined(WEBRTC_POSIX)
#include <errno.h>
#define LAST_SYSTEM_ERROR (errno)
#endif  // WEBRTC_WIN

#include "rtc_base/checks.h"

#if defined(_MSC_VER)
// Warning C4722: destructor never returns, potential memory leak.
// FatalMessage's dtor very intentionally aborts.
#pragma warning(disable:4722)
#endif

namespace rtc {
namespace {

void VPrintError(const char* format, va_list args) {
#if defined(WEBRTC_ANDROID)
  __android_log_vprint(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, format, args);
#else
  vfprintf(stderr, format, args);
#endif
}

#if defined(__GNUC__)
void PrintError(const char* format, ...)
    __attribute__((__format__(__printf__, 1, 2)));
#endif

void PrintError(const char* format, ...) {
  va_list args;
  va_start(args, format);
  VPrintError(format, args);
  va_end(args);
}

}  // namespace

FatalMessage::FatalMessage(const char* file, int line) {
  Init(file, line);
}

FatalMessage::FatalMessage(const char* file, int line, std::string* result) {
  Init(file, line);
  stream_ << "Check failed: " << *result << std::endl << "# ";
  delete result;
}

NO_RETURN FatalMessage::~FatalMessage() {
  fflush(stdout);
  fflush(stderr);
  stream_ << std::endl << "#" << std::endl;
  PrintError("%s", stream_.str().c_str());
  fflush(stderr);
  abort();
}

void FatalMessage::Init(const char* file, int line) {
  stream_ << std::endl
          << std::endl
          << "#" << std::endl
          << "# Fatal error in " << file << ", line " << line << std::endl
          << "# last system error: " << LAST_SYSTEM_ERROR << std::endl
          << "# ";
}

// MSVC doesn't like complex extern templates and DLLs.
#if !defined(COMPILER_MSVC)
// Explicit instantiations for commonly used comparisons.
template std::string* MakeCheckOpString<int, int>(
    const int&, const int&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned long>(
    const unsigned long&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned int>(
    const unsigned long&, const unsigned int&, const char* names);
template std::string* MakeCheckOpString<unsigned int, unsigned long>(
    const unsigned int&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<std::string, std::string>(
    const std::string&, const std::string&, const char* name);
#endif

}  // namespace rtc

// Function to call from the C version of the RTC_CHECK and RTC_DCHECK macros.
NO_RETURN void rtc_FatalMessage(const char* file, int line, const char* msg) {
  rtc::FatalMessage(file, line).stream() << msg;
}
<|endoftext|>


<commit_before>/**
 * \file
 * \brief ThreadControlBlock class header
 *
 * \author Copyright (C) 2014-2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-06-30
 */

#ifndef INCLUDE_DISTORTOS_SCHEDULER_THREADCONTROLBLOCK_HPP_
#define INCLUDE_DISTORTOS_SCHEDULER_THREADCONTROLBLOCK_HPP_

#include "distortos/scheduler/RoundRobinQuantum.hpp"
#include "distortos/scheduler/ThreadControlBlockList-types.hpp"
#include "distortos/scheduler/MutexControlBlockList.hpp"

#include "distortos/architecture/Stack.hpp"

#include "distortos/SchedulingPolicy.hpp"

#include "distortos/estd/TypeErasedFunctor.hpp"

namespace distortos
{

class SignalsReceiver;

namespace synchronization
{

class SignalsReceiverControlBlock;

}	// namespace synchronization

namespace scheduler
{

class ThreadControlBlockList;
class ThreadGroupControlBlock;

/// ThreadControlBlock class is a simple description of a Thread
class ThreadControlBlock
{
public:

	/// state of the thread
	enum class State : uint8_t
	{
		/// state in which thread is created, before being added to Scheduler
		New,
		/// thread is runnable
		Runnable,
		/// thread is terminated
		Terminated,
		/// thread is sleeping
		Sleeping,
		/// thread is blocked on Semaphore
		BlockedOnSemaphore,
		/// thread is suspended
		Suspended,
		/// thread is blocked on Mutex
		BlockedOnMutex,
		/// thread is blocked on ConditionVariable
		BlockedOnConditionVariable,
		/// thread is waiting for signal
		WaitingForSignal,
	};

	/// reason of thread unblocking
	enum class UnblockReason : uint8_t
	{
		/// explicit request to unblock the thread - normal unblock
		UnblockRequest,
		/// timeout - unblock via software timer
		Timeout,
		/// signal handler - unblock to deliver unmasked signal
		Signal,
	};

	/// type of object used as storage for ThreadControlBlockList elements - 3 pointers
	using Link = std::array<std::aligned_storage<sizeof(void*), alignof(void*)>::type, 3>;

	/// UnblockFunctor is a functor executed when unblocking the thread, it receives two parameter - a reference to
	/// ThreadControlBlock that is being unblocked and the reason of thread unblocking
	class UnblockFunctor : public estd::TypeErasedFunctor<void(ThreadControlBlock&, UnblockReason)>
	{

	};

	/**
	 * \brief ThreadControlBlock constructor.
	 *
	 * \param [in] stack is an rvalue reference to architecture::Stack object which will be adopted for this thread
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] threadGroupControlBlock is a pointer to scheduler::ThreadGroupControlBlock to which this object will
	 * be added, nullptr to inherit thread group from currently running thread
	 * \param [in] signalsReceiver is a pointer to SignalsReceiver object for this thread, nullptr to disable reception
	 * of signals for this thread
	 * \param [in] owner is a reference to ThreadBase object that owns this ThreadControlBlock
	 */

	ThreadControlBlock(architecture::Stack&& stack, uint8_t priority, SchedulingPolicy schedulingPolicy,
			ThreadGroupControlBlock* threadGroupControlBlock, SignalsReceiver* signalsReceiver, ThreadBase& owner);

	/**
	 * \brief ThreadControlBlock's destructor
	 */

	~ThreadControlBlock();

	/**
	 * \brief Hook function executed when thread is added to scheduler.
	 *
	 * If threadGroupControlBlock_ is nullptr, it is inherited from currently running thread. Then this object is added
	 * to the thread group (if it is valid).
	 *
	 * \attention This function should be called only by Scheduler::addInternal().
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - inherited thread group is invalid;
	 */

	int addHook();

	/**
	 * \brief Block hook function of thread
	 *
	 * Saves pointer to UnblockFunctor.
	 *
	 * \attention This function should be called only by Scheduler::blockInternal().
	 *
	 * \param [in] unblockFunctor is a pointer to UnblockFunctor which will be executed in unblockHook()
	 */

	void blockHook(const UnblockFunctor* const unblockFunctor)
	{
		unblockFunctor_ = unblockFunctor;
	}

	/**
	 * \return effective priority of ThreadControlBlock
	 */

	uint8_t getEffectivePriority() const
	{
		return std::max(priority_, boostedPriority_);
	}

	/**
	 * \return iterator to the element on the list, valid only when list_ != nullptr
	 */

	ThreadControlBlockListIterator getIterator() const
	{
		return iterator_;
	}

	/**
	 * \return reference to internal storage for list link
	 */

	Link& getLink()
	{
		return link_;
	}

	/**
	 * \return pointer to list that has this object
	 */

	ThreadControlBlockList* getList() const
	{
		return list_;
	}

	/**
	 * \return reference to list of mutex control blocks with enabled priority protocol owned by this thread
	 */

	MutexControlBlockList& getOwnedProtocolMutexControlBlocksList()
	{
		return ownedProtocolMutexControlBlocksList_;
	}

	/**
	 * \return reference to ThreadBase object that owns this ThreadControlBlock
	 */

	ThreadBase& getOwner() const
	{
		return owner_;
	}

	/**
	 * \return priority of ThreadControlBlock
	 */

	uint8_t getPriority() const
	{
		return priority_;
	}

	/**
	 * \return reference to internal RoundRobinQuantum object
	 */

	RoundRobinQuantum& getRoundRobinQuantum()
	{
		return roundRobinQuantum_;
	}

	/**
	 * \return scheduling policy of the thread
	 */

	SchedulingPolicy getSchedulingPolicy() const
	{
		return schedulingPolicy_;
	}

	/**
	 * \return pointer to synchronization::SignalsReceiverControlBlock object for this thread, nullptr if this thread
	 * cannot receive signals
	 */

	synchronization::SignalsReceiverControlBlock* getSignalsReceiverControlBlock() const
	{
		return signalsReceiverControlBlock_;
	}

	/**
	 * \return reference to internal Stack object
	 */

	architecture::Stack& getStack()
	{
		return stack_;
	}

	/**
	 * \return current state of object
	 */

	State getState() const
	{
		return state_;
	}

	/**
	 * \return reference to internal storage for thread group list link
	 */

	Link& getThreadGroupLink()
	{
		return threadGroupLink_;
	}

	/**
	 * \brief Sets the iterator to the element on the list.
	 *
	 * \param [in] iterator is an iterator to the element on the list
	 */

	void setIterator(const ThreadControlBlockListIterator iterator)
	{
		iterator_ = iterator;
	}

	/**
	 * \brief Sets the list that has this object.
	 *
	 * \param [in] list is a pointer to list that has this object
	 */

	void setList(ThreadControlBlockList* const list)
	{
		list_ = list;
	}

	/**
	 * \brief Changes priority of thread.
	 *
	 * If the priority really changes, the position in the thread list is adjusted and context switch may be requested.
	 *
	 * \param [in] priority is the new priority of thread
	 * \param [in] alwaysBehind selects the method of ordering when lowering the priority
	 * - false - the thread is moved to the head of the group of threads with the new priority (default),
	 * - true - the thread is moved to the tail of the group of threads with the new priority.
	 */

	void setPriority(uint8_t priority, bool alwaysBehind = {});

	/**
	 * \param [in] priorityInheritanceMutexControlBlock is a pointer to MutexControlBlock (with PriorityInheritance
	 * protocol) that blocks this thread
	 */

	void setPriorityInheritanceMutexControlBlock(const synchronization::MutexControlBlock* const
			priorityInheritanceMutexControlBlock)
	{
		priorityInheritanceMutexControlBlock_ = priorityInheritanceMutexControlBlock;
	}

	/**
	 * param [in] schedulingPolicy is the new scheduling policy of the thread
	 */

	void setSchedulingPolicy(SchedulingPolicy schedulingPolicy);

	/**
	 * \param [in] state is the new state of object
	 */

	void setState(const State state)
	{
		state_ = state;
	}

	/**
	 * \brief Hook function called when context is switched to this thread.
	 *
	 * Sets global _impure_ptr (from newlib) to thread's \a reent_ member variable.
	 *
	 * \attention This function should be called only by Scheduler::switchContext().
	 */

	void switchedToHook()
	{
		_impure_ptr = &reent_;
	}

	/**
	 * \brief Unblock hook function of thread
	 *
	 * Resets round-robin's quantum and executes unblock functor saved in blockHook().
	 *
	 * \attention This function should be called only by Scheduler::unblockInternal().
	 *
	 * \param [in] unblockReason is the new reason of unblocking of the thread
	 */

	void unblockHook(UnblockReason unblockReason);

	/**
	 * \brief Updates boosted priority of the thread.
	 *
	 * This function should be called after all operations involving this thread and a mutex with enabled priority
	 * protocol.
	 *
	 * \param [in] boostedPriority is the initial boosted priority, this should be effective priority of the thread that
	 * is about to be blocked on a mutex owned by this thread, default - 0
	 */

	void updateBoostedPriority(uint8_t boostedPriority = {});

	ThreadControlBlock(const ThreadControlBlock&) = delete;
	ThreadControlBlock(ThreadControlBlock&&) = default;
	const ThreadControlBlock& operator=(const ThreadControlBlock&) = delete;
	ThreadControlBlock& operator=(ThreadControlBlock&&) = delete;

private:

	/**
	 * \brief Repositions the thread on the list it's currently on.
	 *
	 * This function should be called when thread's effective priority changes.
	 *
	 * \attention list_ must not be nullptr
	 *
	 * \param [in] loweringBefore selects the method of ordering when lowering the priority (it must be false when the
	 * priority is raised!):
	 * - true - the thread is moved to the head of the group of threads with the new priority, this is accomplished by
	 * temporarily boosting effective priority by 1,
	 * - false - the thread is moved to the tail of the group of threads with the new priority.
	 */

	void reposition(bool loweringBefore);

	/// internal stack object
	architecture::Stack stack_;

	/// storage for list link
	Link link_;

	/// storage for thread group list link
	Link threadGroupLink_;

	/// reference to ThreadBase object that owns this ThreadControlBlock
	ThreadBase& owner_;

	/// list of mutex control blocks with enabled priority protocol owned by this thread
	MutexControlBlockList ownedProtocolMutexControlBlocksList_;

	/// pointer to MutexControlBlock (with PriorityInheritance protocol) that blocks this thread
	const synchronization::MutexControlBlock* priorityInheritanceMutexControlBlock_;

	/// pointer to list that has this object
	ThreadControlBlockList* list_;

	/// iterator to the element on the list, valid only when list_ != nullptr
	ThreadControlBlockListIterator iterator_;

	/// pointer to ThreadGroupControlBlock with which this object is associated
	ThreadGroupControlBlock* threadGroupControlBlock_;

	/// pointer to ThreadGroupControlBlock's list that has this object
	ThreadControlBlockUnsortedList* threadGroupList_;

	/// iterator to the element on the ThreadGroupControlBlock's list, valid only when threadGroupList_ != nullptr
	ThreadControlBlockListIterator threadGroupIterator_;

	/// functor executed in unblockHook()
	const UnblockFunctor* unblockFunctor_;

	/// pointer to synchronization::SignalsReceiverControlBlock object for this thread, nullptr if this thread cannot
	/// receive signals
	synchronization::SignalsReceiverControlBlock* signalsReceiverControlBlock_;

	/// newlib's _reent structure with thread-specific data
	_reent reent_;

	/// thread's priority, 0 - lowest, UINT8_MAX - highest
	uint8_t priority_;

	/// thread's boosted priority, 0 - no boosting
	uint8_t boostedPriority_;

	/// round-robin quantum
	RoundRobinQuantum roundRobinQuantum_;

	/// scheduling policy of the thread
	SchedulingPolicy schedulingPolicy_;

	/// current state of object
	State state_;
};

}	// namespace scheduler

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_SCHEDULER_THREADCONTROLBLOCK_HPP_
<commit_msg>ThreadControlBlock::State: add new value - ThreadControlBlock::State::BlockedOnOnceFlag<commit_after>/**
 * \file
 * \brief ThreadControlBlock class header
 *
 * \author Copyright (C) 2014-2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-07-09
 */

#ifndef INCLUDE_DISTORTOS_SCHEDULER_THREADCONTROLBLOCK_HPP_
#define INCLUDE_DISTORTOS_SCHEDULER_THREADCONTROLBLOCK_HPP_

#include "distortos/scheduler/RoundRobinQuantum.hpp"
#include "distortos/scheduler/ThreadControlBlockList-types.hpp"
#include "distortos/scheduler/MutexControlBlockList.hpp"

#include "distortos/architecture/Stack.hpp"

#include "distortos/SchedulingPolicy.hpp"

#include "distortos/estd/TypeErasedFunctor.hpp"

namespace distortos
{

class SignalsReceiver;

namespace synchronization
{

class SignalsReceiverControlBlock;

}	// namespace synchronization

namespace scheduler
{

class ThreadControlBlockList;
class ThreadGroupControlBlock;

/// ThreadControlBlock class is a simple description of a Thread
class ThreadControlBlock
{
public:

	/// state of the thread
	enum class State : uint8_t
	{
		/// state in which thread is created, before being added to Scheduler
		New,
		/// thread is runnable
		Runnable,
		/// thread is terminated
		Terminated,
		/// thread is sleeping
		Sleeping,
		/// thread is blocked on Semaphore
		BlockedOnSemaphore,
		/// thread is suspended
		Suspended,
		/// thread is blocked on Mutex
		BlockedOnMutex,
		/// thread is blocked on ConditionVariable
		BlockedOnConditionVariable,
		/// thread is waiting for signal
		WaitingForSignal,
		/// thread is blocked on OnceFlag
		BlockedOnOnceFlag
	};

	/// reason of thread unblocking
	enum class UnblockReason : uint8_t
	{
		/// explicit request to unblock the thread - normal unblock
		UnblockRequest,
		/// timeout - unblock via software timer
		Timeout,
		/// signal handler - unblock to deliver unmasked signal
		Signal,
	};

	/// type of object used as storage for ThreadControlBlockList elements - 3 pointers
	using Link = std::array<std::aligned_storage<sizeof(void*), alignof(void*)>::type, 3>;

	/// UnblockFunctor is a functor executed when unblocking the thread, it receives two parameter - a reference to
	/// ThreadControlBlock that is being unblocked and the reason of thread unblocking
	class UnblockFunctor : public estd::TypeErasedFunctor<void(ThreadControlBlock&, UnblockReason)>
	{

	};

	/**
	 * \brief ThreadControlBlock constructor.
	 *
	 * \param [in] stack is an rvalue reference to architecture::Stack object which will be adopted for this thread
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] threadGroupControlBlock is a pointer to scheduler::ThreadGroupControlBlock to which this object will
	 * be added, nullptr to inherit thread group from currently running thread
	 * \param [in] signalsReceiver is a pointer to SignalsReceiver object for this thread, nullptr to disable reception
	 * of signals for this thread
	 * \param [in] owner is a reference to ThreadBase object that owns this ThreadControlBlock
	 */

	ThreadControlBlock(architecture::Stack&& stack, uint8_t priority, SchedulingPolicy schedulingPolicy,
			ThreadGroupControlBlock* threadGroupControlBlock, SignalsReceiver* signalsReceiver, ThreadBase& owner);

	/**
	 * \brief ThreadControlBlock's destructor
	 */

	~ThreadControlBlock();

	/**
	 * \brief Hook function executed when thread is added to scheduler.
	 *
	 * If threadGroupControlBlock_ is nullptr, it is inherited from currently running thread. Then this object is added
	 * to the thread group (if it is valid).
	 *
	 * \attention This function should be called only by Scheduler::addInternal().
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - inherited thread group is invalid;
	 */

	int addHook();

	/**
	 * \brief Block hook function of thread
	 *
	 * Saves pointer to UnblockFunctor.
	 *
	 * \attention This function should be called only by Scheduler::blockInternal().
	 *
	 * \param [in] unblockFunctor is a pointer to UnblockFunctor which will be executed in unblockHook()
	 */

	void blockHook(const UnblockFunctor* const unblockFunctor)
	{
		unblockFunctor_ = unblockFunctor;
	}

	/**
	 * \return effective priority of ThreadControlBlock
	 */

	uint8_t getEffectivePriority() const
	{
		return std::max(priority_, boostedPriority_);
	}

	/**
	 * \return iterator to the element on the list, valid only when list_ != nullptr
	 */

	ThreadControlBlockListIterator getIterator() const
	{
		return iterator_;
	}

	/**
	 * \return reference to internal storage for list link
	 */

	Link& getLink()
	{
		return link_;
	}

	/**
	 * \return pointer to list that has this object
	 */

	ThreadControlBlockList* getList() const
	{
		return list_;
	}

	/**
	 * \return reference to list of mutex control blocks with enabled priority protocol owned by this thread
	 */

	MutexControlBlockList& getOwnedProtocolMutexControlBlocksList()
	{
		return ownedProtocolMutexControlBlocksList_;
	}

	/**
	 * \return reference to ThreadBase object that owns this ThreadControlBlock
	 */

	ThreadBase& getOwner() const
	{
		return owner_;
	}

	/**
	 * \return priority of ThreadControlBlock
	 */

	uint8_t getPriority() const
	{
		return priority_;
	}

	/**
	 * \return reference to internal RoundRobinQuantum object
	 */

	RoundRobinQuantum& getRoundRobinQuantum()
	{
		return roundRobinQuantum_;
	}

	/**
	 * \return scheduling policy of the thread
	 */

	SchedulingPolicy getSchedulingPolicy() const
	{
		return schedulingPolicy_;
	}

	/**
	 * \return pointer to synchronization::SignalsReceiverControlBlock object for this thread, nullptr if this thread
	 * cannot receive signals
	 */

	synchronization::SignalsReceiverControlBlock* getSignalsReceiverControlBlock() const
	{
		return signalsReceiverControlBlock_;
	}

	/**
	 * \return reference to internal Stack object
	 */

	architecture::Stack& getStack()
	{
		return stack_;
	}

	/**
	 * \return current state of object
	 */

	State getState() const
	{
		return state_;
	}

	/**
	 * \return reference to internal storage for thread group list link
	 */

	Link& getThreadGroupLink()
	{
		return threadGroupLink_;
	}

	/**
	 * \brief Sets the iterator to the element on the list.
	 *
	 * \param [in] iterator is an iterator to the element on the list
	 */

	void setIterator(const ThreadControlBlockListIterator iterator)
	{
		iterator_ = iterator;
	}

	/**
	 * \brief Sets the list that has this object.
	 *
	 * \param [in] list is a pointer to list that has this object
	 */

	void setList(ThreadControlBlockList* const list)
	{
		list_ = list;
	}

	/**
	 * \brief Changes priority of thread.
	 *
	 * If the priority really changes, the position in the thread list is adjusted and context switch may be requested.
	 *
	 * \param [in] priority is the new priority of thread
	 * \param [in] alwaysBehind selects the method of ordering when lowering the priority
	 * - false - the thread is moved to the head of the group of threads with the new priority (default),
	 * - true - the thread is moved to the tail of the group of threads with the new priority.
	 */

	void setPriority(uint8_t priority, bool alwaysBehind = {});

	/**
	 * \param [in] priorityInheritanceMutexControlBlock is a pointer to MutexControlBlock (with PriorityInheritance
	 * protocol) that blocks this thread
	 */

	void setPriorityInheritanceMutexControlBlock(const synchronization::MutexControlBlock* const
			priorityInheritanceMutexControlBlock)
	{
		priorityInheritanceMutexControlBlock_ = priorityInheritanceMutexControlBlock;
	}

	/**
	 * param [in] schedulingPolicy is the new scheduling policy of the thread
	 */

	void setSchedulingPolicy(SchedulingPolicy schedulingPolicy);

	/**
	 * \param [in] state is the new state of object
	 */

	void setState(const State state)
	{
		state_ = state;
	}

	/**
	 * \brief Hook function called when context is switched to this thread.
	 *
	 * Sets global _impure_ptr (from newlib) to thread's \a reent_ member variable.
	 *
	 * \attention This function should be called only by Scheduler::switchContext().
	 */

	void switchedToHook()
	{
		_impure_ptr = &reent_;
	}

	/**
	 * \brief Unblock hook function of thread
	 *
	 * Resets round-robin's quantum and executes unblock functor saved in blockHook().
	 *
	 * \attention This function should be called only by Scheduler::unblockInternal().
	 *
	 * \param [in] unblockReason is the new reason of unblocking of the thread
	 */

	void unblockHook(UnblockReason unblockReason);

	/**
	 * \brief Updates boosted priority of the thread.
	 *
	 * This function should be called after all operations involving this thread and a mutex with enabled priority
	 * protocol.
	 *
	 * \param [in] boostedPriority is the initial boosted priority, this should be effective priority of the thread that
	 * is about to be blocked on a mutex owned by this thread, default - 0
	 */

	void updateBoostedPriority(uint8_t boostedPriority = {});

	ThreadControlBlock(const ThreadControlBlock&) = delete;
	ThreadControlBlock(ThreadControlBlock&&) = default;
	const ThreadControlBlock& operator=(const ThreadControlBlock&) = delete;
	ThreadControlBlock& operator=(ThreadControlBlock&&) = delete;

private:

	/**
	 * \brief Repositions the thread on the list it's currently on.
	 *
	 * This function should be called when thread's effective priority changes.
	 *
	 * \attention list_ must not be nullptr
	 *
	 * \param [in] loweringBefore selects the method of ordering when lowering the priority (it must be false when the
	 * priority is raised!):
	 * - true - the thread is moved to the head of the group of threads with the new priority, this is accomplished by
	 * temporarily boosting effective priority by 1,
	 * - false - the thread is moved to the tail of the group of threads with the new priority.
	 */

	void reposition(bool loweringBefore);

	/// internal stack object
	architecture::Stack stack_;

	/// storage for list link
	Link link_;

	/// storage for thread group list link
	Link threadGroupLink_;

	/// reference to ThreadBase object that owns this ThreadControlBlock
	ThreadBase& owner_;

	/// list of mutex control blocks with enabled priority protocol owned by this thread
	MutexControlBlockList ownedProtocolMutexControlBlocksList_;

	/// pointer to MutexControlBlock (with PriorityInheritance protocol) that blocks this thread
	const synchronization::MutexControlBlock* priorityInheritanceMutexControlBlock_;

	/// pointer to list that has this object
	ThreadControlBlockList* list_;

	/// iterator to the element on the list, valid only when list_ != nullptr
	ThreadControlBlockListIterator iterator_;

	/// pointer to ThreadGroupControlBlock with which this object is associated
	ThreadGroupControlBlock* threadGroupControlBlock_;

	/// pointer to ThreadGroupControlBlock's list that has this object
	ThreadControlBlockUnsortedList* threadGroupList_;

	/// iterator to the element on the ThreadGroupControlBlock's list, valid only when threadGroupList_ != nullptr
	ThreadControlBlockListIterator threadGroupIterator_;

	/// functor executed in unblockHook()
	const UnblockFunctor* unblockFunctor_;

	/// pointer to synchronization::SignalsReceiverControlBlock object for this thread, nullptr if this thread cannot
	/// receive signals
	synchronization::SignalsReceiverControlBlock* signalsReceiverControlBlock_;

	/// newlib's _reent structure with thread-specific data
	_reent reent_;

	/// thread's priority, 0 - lowest, UINT8_MAX - highest
	uint8_t priority_;

	/// thread's boosted priority, 0 - no boosting
	uint8_t boostedPriority_;

	/// round-robin quantum
	RoundRobinQuantum roundRobinQuantum_;

	/// scheduling policy of the thread
	SchedulingPolicy schedulingPolicy_;

	/// current state of object
	State state_;
};

}	// namespace scheduler

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_SCHEDULER_THREADCONTROLBLOCK_HPP_
<|endoftext|>