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

#include "content/browser/power_save_blocker_impl.h"

#include <X11/Xlib.h>
#include <X11/extensions/dpms.h>
// Xlib #defines Status, but we can't have that for some of our headers.
#ifdef Status
#undef Status
#endif

#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/nix/xdg_util.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/browser_thread.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/object_proxy.h"
#include "ui/gfx/x/x11_types.h"

namespace {

enum DBusAPI {
  NO_API,           // Disable. No supported API available.
  GNOME_API,        // Use the GNOME API. (Supports more features.)
  FREEDESKTOP_API,  // Use the FreeDesktop API, for KDE4 and XFCE.
};

// Inhibit flags defined in the org.gnome.SessionManager interface.
// Can be OR'd together and passed as argument to the Inhibit() method
// to specify which power management features we want to suspend.
enum GnomeAPIInhibitFlags {
  INHIBIT_LOGOUT            = 1,
  INHIBIT_SWITCH_USER       = 2,
  INHIBIT_SUSPEND_SESSION   = 4,
  INHIBIT_MARK_SESSION_IDLE = 8
};

const char kGnomeAPIServiceName[] = "org.gnome.SessionManager";
const char kGnomeAPIInterfaceName[] = "org.gnome.SessionManager";
const char kGnomeAPIObjectPath[] = "/org/gnome/SessionManager";

const char kFreeDesktopAPIServiceName[] = "org.freedesktop.PowerManagement";
const char kFreeDesktopAPIInterfaceName[] =
    "org.freedesktop.PowerManagement.Inhibit";
const char kFreeDesktopAPIObjectPath[] =
    "/org/freedesktop/PowerManagement/Inhibit";

}  // namespace

namespace content {

class PowerSaveBlockerImpl::Delegate
    : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
 public:
  // Picks an appropriate D-Bus API to use based on the desktop environment.
  Delegate(PowerSaveBlockerType type, const std::string& description);

  // Post a task to initialize the delegate on the UI thread, which will itself
  // then post a task to apply the power save block on the FILE thread.
  void Init();

  // Post a task to remove the power save block on the FILE thread, unless it
  // hasn't yet been applied, in which case we just prevent it from applying.
  void CleanUp();

 private:
  friend class base::RefCountedThreadSafe<Delegate>;
  ~Delegate() {}

  // Selects an appropriate D-Bus API to use for this object. Must be called on
  // the UI thread. Checks enqueue_apply_ once an API has been selected, and
  // enqueues a call back to ApplyBlock() if it is true. See the comments for
  // enqueue_apply_ below.
  void InitOnUIThread();

  // Apply or remove the power save block, respectively. These methods should be
  // called once each, on the same thread, per instance. They block waiting for
  // the action to complete (with a timeout); the thread must thus allow I/O.
  void ApplyBlock(DBusAPI api);
  void RemoveBlock(DBusAPI api);

  // If DPMS (the power saving system in X11) is not enabled, then we don't want
  // to try to disable power saving, since on some desktop environments that may
  // enable DPMS with very poor default settings (e.g. turning off the display
  // after only 1 second). Must be called on the UI thread.
  static bool DPMSEnabled();

  // Returns an appropriate D-Bus API to use based on the desktop environment.
  // Must be called on the UI thread, as it may call DPMSEnabled() above.
  static DBusAPI SelectAPI();

  const PowerSaveBlockerType type_;
  const std::string description_;

  // Initially, we post a message to the UI thread to select an API. When it
  // finishes, it will post a message to the FILE thread to perform the actual
  // application of the block, unless enqueue_apply_ is false. We set it to
  // false when we post that message, or when RemoveBlock() is called before
  // ApplyBlock() has run. Both api_ and enqueue_apply_ are guarded by lock_.
  DBusAPI api_;
  bool enqueue_apply_;
  base::Lock lock_;

  scoped_refptr<dbus::Bus> bus_;

  // The cookie that identifies our inhibit request,
  // or 0 if there is no active inhibit request.
  uint32 inhibit_cookie_;

  DISALLOW_COPY_AND_ASSIGN(Delegate);
};

PowerSaveBlockerImpl::Delegate::Delegate(PowerSaveBlockerType type,
                                         const std::string& description)
    : type_(type),
      description_(description),
      api_(NO_API),
      enqueue_apply_(false),
      inhibit_cookie_(0) {
  // We're on the client's thread here, so we don't allocate the dbus::Bus
  // object yet. We'll do it later in ApplyBlock(), on the FILE thread.
}

void PowerSaveBlockerImpl::Delegate::Init() {
  base::AutoLock lock(lock_);
  DCHECK(!enqueue_apply_);
  enqueue_apply_ = true;
  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                          base::Bind(&Delegate::InitOnUIThread, this));
}

void PowerSaveBlockerImpl::Delegate::CleanUp() {
  base::AutoLock lock(lock_);
  if (enqueue_apply_) {
    // If a call to ApplyBlock() has not yet been enqueued because we are still
    // initializing on the UI thread, then just cancel it. We don't need to
    // remove the block because we haven't even applied it yet.
    enqueue_apply_ = false;
  } else if (api_ != NO_API) {
    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                            base::Bind(&Delegate::RemoveBlock, this, api_));
  }
}

void PowerSaveBlockerImpl::Delegate::InitOnUIThread() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  base::AutoLock lock(lock_);
  api_ = SelectAPI();
  if (enqueue_apply_ && api_ != NO_API) {
    // The thread we use here becomes the origin and D-Bus thread for the D-Bus
    // library, so we need to use the same thread above for RemoveBlock(). It
    // must be a thread that allows I/O operations, so we use the FILE thread.
    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                            base::Bind(&Delegate::ApplyBlock, this, api_));
  }
  enqueue_apply_ = false;
}

void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  DCHECK(!bus_.get());  // ApplyBlock() should only be called once.

  dbus::Bus::Options options;
  options.bus_type = dbus::Bus::SESSION;
  options.connection_type = dbus::Bus::PRIVATE;
  bus_ = new dbus::Bus(options);

  scoped_refptr<dbus::ObjectProxy> object_proxy;
  scoped_ptr<dbus::MethodCall> method_call;
  scoped_ptr<dbus::MessageWriter> message_writer;

  switch (api) {
    case NO_API:
      NOTREACHED();  // We should never call this method with this value.
      return;
    case GNOME_API:
      object_proxy = bus_->GetObjectProxy(
          kGnomeAPIServiceName,
          dbus::ObjectPath(kGnomeAPIObjectPath));
      method_call.reset(
          new dbus::MethodCall(kGnomeAPIInterfaceName, "Inhibit"));
      message_writer.reset(new dbus::MessageWriter(method_call.get()));
      // The arguments of the method are:
      //     app_id:        The application identifier
      //     toplevel_xid:  The toplevel X window identifier
      //     reason:        The reason for the inhibit
      //     flags:         Flags that spefify what should be inhibited
      message_writer->AppendString(
          base::CommandLine::ForCurrentProcess()->GetProgram().value());
      message_writer->AppendUint32(0);  // should be toplevel_xid
      message_writer->AppendString(description_);
      {
        uint32 flags = 0;
        switch (type_) {
          case kPowerSaveBlockPreventDisplaySleep:
            flags |= INHIBIT_MARK_SESSION_IDLE;
            flags |= INHIBIT_SUSPEND_SESSION;
            break;
          case kPowerSaveBlockPreventAppSuspension:
            flags |= INHIBIT_SUSPEND_SESSION;
            break;
        }
        message_writer->AppendUint32(flags);
      }
      break;
    case FREEDESKTOP_API:
      object_proxy = bus_->GetObjectProxy(
          kFreeDesktopAPIServiceName,
          dbus::ObjectPath(kFreeDesktopAPIObjectPath));
      method_call.reset(
          new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "Inhibit"));
      message_writer.reset(new dbus::MessageWriter(method_call.get()));
      // The arguments of the method are:
      //     app_id:        The application identifier
      //     reason:        The reason for the inhibit
      message_writer->AppendString(
          base::CommandLine::ForCurrentProcess()->GetProgram().value());
      message_writer->AppendString(description_);
      break;
  }

  // We could do this method call asynchronously, but if we did, we'd need to
  // handle the case where we want to cancel the block before we get a reply.
  // We're on the FILE thread so it should be OK to block briefly here.
  scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
      method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
  if (response) {
    // The method returns an inhibit_cookie, used to uniquely identify
    // this request. It should be used as an argument to Uninhibit()
    // in order to remove the request.
    dbus::MessageReader message_reader(response.get());
    if (!message_reader.PopUint32(&inhibit_cookie_))
      LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString();
  } else {
    LOG(ERROR) << "No response to Inhibit() request!";
  }
}

void PowerSaveBlockerImpl::Delegate::RemoveBlock(DBusAPI api) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  DCHECK(bus_.get());  // RemoveBlock() should only be called once.

  scoped_refptr<dbus::ObjectProxy> object_proxy;
  scoped_ptr<dbus::MethodCall> method_call;

  switch (api) {
    case NO_API:
      NOTREACHED();  // We should never call this method with this value.
      return;
    case GNOME_API:
      object_proxy = bus_->GetObjectProxy(
          kGnomeAPIServiceName,
          dbus::ObjectPath(kGnomeAPIObjectPath));
      method_call.reset(
          new dbus::MethodCall(kGnomeAPIInterfaceName, "Uninhibit"));
      break;
    case FREEDESKTOP_API:
      object_proxy = bus_->GetObjectProxy(
          kFreeDesktopAPIServiceName,
          dbus::ObjectPath(kFreeDesktopAPIObjectPath));
      method_call.reset(
          new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "UnInhibit"));
      break;
  }

  dbus::MessageWriter message_writer(method_call.get());
  message_writer.AppendUint32(inhibit_cookie_);
  scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
      method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
  if (!response)
    LOG(ERROR) << "No response to Uninhibit() request!";
  // We don't care about checking the result. We assume it works; we can't
  // really do anything about it anyway if it fails.
  inhibit_cookie_ = 0;

  bus_->ShutdownAndBlock();
  bus_ = NULL;
}

// static
bool PowerSaveBlockerImpl::Delegate::DPMSEnabled() {
  XDisplay* display = gfx::GetXDisplay();
  BOOL enabled = false;
  int dummy;
  if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) {
    CARD16 state;
    DPMSInfo(display, &state, &enabled);
  }
  return enabled;
}

// static
DBusAPI PowerSaveBlockerImpl::Delegate::SelectAPI() {
  scoped_ptr<base::Environment> env(base::Environment::Create());
  switch (base::nix::GetDesktopEnvironment(env.get())) {
    case base::nix::DESKTOP_ENVIRONMENT_GNOME:
    case base::nix::DESKTOP_ENVIRONMENT_UNITY:
      if (DPMSEnabled())
        return GNOME_API;
      break;
    case base::nix::DESKTOP_ENVIRONMENT_XFCE:
    case base::nix::DESKTOP_ENVIRONMENT_KDE4:
      if (DPMSEnabled())
        return FREEDESKTOP_API;
      break;
    case base::nix::DESKTOP_ENVIRONMENT_KDE3:
    case base::nix::DESKTOP_ENVIRONMENT_OTHER:
      // Not supported.
      break;
  }
  return NO_API;
}

PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
                                           Reason reason,
                                           const std::string& description)
    : delegate_(new Delegate(type, description)) {
  delegate_->Init();
}

PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
  delegate_->CleanUp();
}

}  // namespace content
<commit_msg>Make D-bus power save suspension calls asynchronous. On some systems with buggy power managers, calls to the power manager would result in long pauses that would block the FILE thread. This yielded degraded performance for other browser tasks scheduled on the same thread.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/power_save_blocker_impl.h"

#include <X11/Xlib.h>
#include <X11/extensions/dpms.h>
// Xlib #defines Status, but we can't have that for some of our headers.
#ifdef Status
#undef Status
#endif

#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/nix/xdg_util.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/browser_thread.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/object_proxy.h"
#include "ui/gfx/x/x11_types.h"

namespace {

enum DBusAPI {
  NO_API,           // Disable. No supported API available.
  GNOME_API,        // Use the GNOME API. (Supports more features.)
  FREEDESKTOP_API,  // Use the FreeDesktop API, for KDE4 and XFCE.
};

// Inhibit flags defined in the org.gnome.SessionManager interface.
// Can be OR'd together and passed as argument to the Inhibit() method
// to specify which power management features we want to suspend.
enum GnomeAPIInhibitFlags {
  INHIBIT_LOGOUT            = 1,
  INHIBIT_SWITCH_USER       = 2,
  INHIBIT_SUSPEND_SESSION   = 4,
  INHIBIT_MARK_SESSION_IDLE = 8
};

const char kGnomeAPIServiceName[] = "org.gnome.SessionManager";
const char kGnomeAPIInterfaceName[] = "org.gnome.SessionManager";
const char kGnomeAPIObjectPath[] = "/org/gnome/SessionManager";

const char kFreeDesktopAPIServiceName[] = "org.freedesktop.PowerManagement";
const char kFreeDesktopAPIInterfaceName[] =
    "org.freedesktop.PowerManagement.Inhibit";
const char kFreeDesktopAPIObjectPath[] =
    "/org/freedesktop/PowerManagement/Inhibit";

}  // namespace

namespace content {

class PowerSaveBlockerImpl::Delegate
    : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
 public:
  // Picks an appropriate D-Bus API to use based on the desktop environment.
  Delegate(PowerSaveBlockerType type, const std::string& description);

  // Post a task to initialize the delegate on the UI thread, which will itself
  // then post a task to apply the power save block on the FILE thread.
  void Init();

  // Post a task to remove the power save block on the FILE thread, unless it
  // hasn't yet been applied, in which case we just prevent it from applying.
  void CleanUp();

 private:
  friend class base::RefCountedThreadSafe<Delegate>;
  ~Delegate() {}

  // Selects an appropriate D-Bus API to use for this object. Must be called on
  // the UI thread. Checks enqueue_apply_ once an API has been selected, and
  // enqueues a call back to ApplyBlock() if it is true. See the comments for
  // enqueue_apply_ below.
  void InitOnUIThread();

  // Apply or remove the power save block, respectively. These methods should be
  // called once each, on the same thread, per instance. They block waiting for
  // the action to complete (with a timeout); the thread must thus allow I/O.
  void ApplyBlock(DBusAPI api);
  void RemoveBlock(DBusAPI api);

  // Asynchronous callback functions for ApplyBlock and RemoveBlock.
  // Functions do not receive ownership of |response|.
  void ApplyBlockFinished(DBusAPI api, dbus::Response* response);
  void RemoveBlockFinished(dbus::Response* response);

  // If DPMS (the power saving system in X11) is not enabled, then we don't want
  // to try to disable power saving, since on some desktop environments that may
  // enable DPMS with very poor default settings (e.g. turning off the display
  // after only 1 second). Must be called on the UI thread.
  static bool DPMSEnabled();

  // Returns an appropriate D-Bus API to use based on the desktop environment.
  // Must be called on the UI thread, as it may call DPMSEnabled() above.
  static DBusAPI SelectAPI();

  const PowerSaveBlockerType type_;
  const std::string description_;

  // Initially, we post a message to the UI thread to select an API. When it
  // finishes, it will post a message to the FILE thread to perform the actual
  // application of the block, unless enqueue_apply_ is false. We set it to
  // false when we post that message, or when RemoveBlock() is called before
  // ApplyBlock() has run. Both api_ and enqueue_apply_ are guarded by lock_.
  DBusAPI api_;
  bool enqueue_apply_;
  base::Lock lock_;

  // Indicates that a D-Bus power save blocking request is in flight.
  bool block_inflight_;
  // Used to detect erronous redundant calls to RemoveBlock().
  bool unblock_inflight_;
  // Indicates that RemoveBlock() is called before ApplyBlock() has finished.
  // If it's true, then the RemoveBlock() call will be processed immediately
  // after ApplyBlock() has finished.
  bool enqueue_unblock_;

  scoped_refptr<dbus::Bus> bus_;

  // The cookie that identifies our inhibit request,
  // or 0 if there is no active inhibit request.
  uint32 inhibit_cookie_;

  DISALLOW_COPY_AND_ASSIGN(Delegate);
};

PowerSaveBlockerImpl::Delegate::Delegate(PowerSaveBlockerType type,
                                         const std::string& description)
    : type_(type),
      description_(description),
      api_(NO_API),
      enqueue_apply_(false),
      inhibit_cookie_(0) {
  // We're on the client's thread here, so we don't allocate the dbus::Bus
  // object yet. We'll do it later in ApplyBlock(), on the FILE thread.
}

void PowerSaveBlockerImpl::Delegate::Init() {
  base::AutoLock lock(lock_);
  DCHECK(!enqueue_apply_);
  enqueue_apply_ = true;
  block_inflight_ = false;
  unblock_inflight_ = false;
  enqueue_unblock_ = false;
  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                          base::Bind(&Delegate::InitOnUIThread, this));
}

void PowerSaveBlockerImpl::Delegate::CleanUp() {
  base::AutoLock lock(lock_);
  if (enqueue_apply_) {
    // If a call to ApplyBlock() has not yet been enqueued because we are still
    // initializing on the UI thread, then just cancel it. We don't need to
    // remove the block because we haven't even applied it yet.
    enqueue_apply_ = false;
  } else if (api_ != NO_API) {
    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                            base::Bind(&Delegate::RemoveBlock, this, api_));
  }
}

void PowerSaveBlockerImpl::Delegate::InitOnUIThread() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  base::AutoLock lock(lock_);
  api_ = SelectAPI();
  if (enqueue_apply_ && api_ != NO_API) {
    // The thread we use here becomes the origin and D-Bus thread for the D-Bus
    // library, so we need to use the same thread above for RemoveBlock(). It
    // must be a thread that allows I/O operations, so we use the FILE thread.
    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                            base::Bind(&Delegate::ApplyBlock, this, api_));
  }
  enqueue_apply_ = false;
}

void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  DCHECK(!bus_);  // ApplyBlock() should only be called once.
  DCHECK(!block_inflight_);

  dbus::Bus::Options options;
  options.bus_type = dbus::Bus::SESSION;
  options.connection_type = dbus::Bus::PRIVATE;
  bus_ = new dbus::Bus(options);

  scoped_refptr<dbus::ObjectProxy> object_proxy;
  scoped_ptr<dbus::MethodCall> method_call;
  scoped_ptr<dbus::MessageWriter> message_writer;

  switch (api) {
    case NO_API:
      NOTREACHED();  // We should never call this method with this value.
      return;
    case GNOME_API:
      object_proxy = bus_->GetObjectProxy(
          kGnomeAPIServiceName,
          dbus::ObjectPath(kGnomeAPIObjectPath));
      method_call.reset(
          new dbus::MethodCall(kGnomeAPIInterfaceName, "Inhibit"));
      message_writer.reset(new dbus::MessageWriter(method_call.get()));
      // The arguments of the method are:
      //     app_id:        The application identifier
      //     toplevel_xid:  The toplevel X window identifier
      //     reason:        The reason for the inhibit
      //     flags:         Flags that spefify what should be inhibited
      message_writer->AppendString(
          base::CommandLine::ForCurrentProcess()->GetProgram().value());
      message_writer->AppendUint32(0);  // should be toplevel_xid
      message_writer->AppendString(description_);
      {
        uint32 flags = 0;
        switch (type_) {
          case kPowerSaveBlockPreventDisplaySleep:
            flags |= INHIBIT_MARK_SESSION_IDLE;
            flags |= INHIBIT_SUSPEND_SESSION;
            break;
          case kPowerSaveBlockPreventAppSuspension:
            flags |= INHIBIT_SUSPEND_SESSION;
            break;
        }
        message_writer->AppendUint32(flags);
      }
      break;
    case FREEDESKTOP_API:
      object_proxy = bus_->GetObjectProxy(
          kFreeDesktopAPIServiceName,
          dbus::ObjectPath(kFreeDesktopAPIObjectPath));
      method_call.reset(
          new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "Inhibit"));
      message_writer.reset(new dbus::MessageWriter(method_call.get()));
      // The arguments of the method are:
      //     app_id:        The application identifier
      //     reason:        The reason for the inhibit
      message_writer->AppendString(
          base::CommandLine::ForCurrentProcess()->GetProgram().value());
      message_writer->AppendString(description_);
      break;
  }

  block_inflight_ = true;
  object_proxy->CallMethod(
      method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
      base::Bind(&PowerSaveBlockerImpl::Delegate::ApplyBlockFinished, this,
                 api));
}

void PowerSaveBlockerImpl::Delegate::ApplyBlockFinished(
    DBusAPI api,
    dbus::Response* response) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  DCHECK(bus_);
  DCHECK(block_inflight_);
  block_inflight_ = false;

  if (response) {
    // The method returns an inhibit_cookie, used to uniquely identify
    // this request. It should be used as an argument to Uninhibit()
    // in order to remove the request.
    dbus::MessageReader message_reader(response);
    if (!message_reader.PopUint32(&inhibit_cookie_))
      LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString();
  } else {
    LOG(ERROR) << "No response to Inhibit() request!";
  }

  if (enqueue_unblock_) {
    enqueue_unblock_ = false;
    // RemoveBlock() was called while the Inhibit operation was in flight,
    // so go ahead and remove the block now.
    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                            base::Bind(&Delegate::RemoveBlock, this, api_));
  }
}

void PowerSaveBlockerImpl::Delegate::RemoveBlock(DBusAPI api) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  DCHECK(bus_);  // RemoveBlock() should only be called once.
  DCHECK(!unblock_inflight_);

  if (block_inflight_) {
    DCHECK(!enqueue_unblock_);
    // Can't call RemoveBlock until ApplyBlock's async operation has
    // finished. Enqueue it for execution once ApplyBlock is done.
    enqueue_unblock_ = true;
    return;
  }

  scoped_refptr<dbus::ObjectProxy> object_proxy;
  scoped_ptr<dbus::MethodCall> method_call;

  switch (api) {
    case NO_API:
      NOTREACHED();  // We should never call this method with this value.
      return;
    case GNOME_API:
      object_proxy = bus_->GetObjectProxy(
          kGnomeAPIServiceName,
          dbus::ObjectPath(kGnomeAPIObjectPath));
      method_call.reset(
          new dbus::MethodCall(kGnomeAPIInterfaceName, "Uninhibit"));
      break;
    case FREEDESKTOP_API:
      object_proxy = bus_->GetObjectProxy(
          kFreeDesktopAPIServiceName,
          dbus::ObjectPath(kFreeDesktopAPIObjectPath));
      method_call.reset(
          new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "UnInhibit"));
      break;
  }

  dbus::MessageWriter message_writer(method_call.get());
  message_writer.AppendUint32(inhibit_cookie_);
  unblock_inflight_ = true;
  object_proxy->CallMethod(
      method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
      base::Bind(&PowerSaveBlockerImpl::Delegate::RemoveBlockFinished, this));
}

void PowerSaveBlockerImpl::Delegate::RemoveBlockFinished(
    dbus::Response* response) {
  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
  DCHECK(bus_);
  unblock_inflight_ = false;

  if (!response)
    LOG(ERROR) << "No response to Uninhibit() request!";
  // We don't care about checking the result. We assume it works; we can't
  // really do anything about it anyway if it fails.
  inhibit_cookie_ = 0;

  bus_->ShutdownAndBlock();
  bus_ = NULL;
}

// static
bool PowerSaveBlockerImpl::Delegate::DPMSEnabled() {
  XDisplay* display = gfx::GetXDisplay();
  BOOL enabled = false;
  int dummy;
  if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) {
    CARD16 state;
    DPMSInfo(display, &state, &enabled);
  }
  return enabled;
}

// static
DBusAPI PowerSaveBlockerImpl::Delegate::SelectAPI() {
  scoped_ptr<base::Environment> env(base::Environment::Create());
  switch (base::nix::GetDesktopEnvironment(env.get())) {
    case base::nix::DESKTOP_ENVIRONMENT_GNOME:
    case base::nix::DESKTOP_ENVIRONMENT_UNITY:
      if (DPMSEnabled())
        return GNOME_API;
      break;
    case base::nix::DESKTOP_ENVIRONMENT_XFCE:
    case base::nix::DESKTOP_ENVIRONMENT_KDE4:
      if (DPMSEnabled())
        return FREEDESKTOP_API;
      break;
    case base::nix::DESKTOP_ENVIRONMENT_KDE3:
    case base::nix::DESKTOP_ENVIRONMENT_OTHER:
      // Not supported.
      break;
  }
  return NO_API;
}

PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
                                           Reason reason,
                                           const std::string& description)
    : delegate_(new Delegate(type, description)) {
  delegate_->Init();
}

PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
  delegate_->CleanUp();
}

}  // namespace content
<|endoftext|>


<commit_before>#include "Pickup.hpp"
#include "Weapon.hpp"
#include "../Math.hpp"
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
#include <Kunlaboro/EntitySystem.hpp>
#include <random>
#include <cmath>

Pickup::Pickup() : Kunlaboro::Component("Game.Pickup"), mAngle(0), mTexture(nullptr), mLifeTime(0)
{
}

Pickup::~Pickup()
{
}

void Pickup::addedToEntity()
{
    {
        std::random_device dev;

        mAngle = std::uniform_real_distribution<float>(0, M_PI*2)(dev);
        mInertia = std::uniform_real_distribution<float>(64, 256)(dev);

        mStartAngle = mAngle;
    }

    requestMessage("Event.Update", [this](const Kunlaboro::Message& msg)
    {
        float dt = boost::any_cast<float>(msg.payload);

        if (mInertia > 0)
        {
            mPosition += sf::Vector2f(cos(mStartAngle), sin(mStartAngle)) * mInertia * dt;
            mAngle += mInertia * dt * (M_PI/180);
            mInertia -= dt * 100;
        }
        else
        {
            mLifeTime += dt;

            if (mLifeTime > 10)
                getEntitySystem()->destroyEntity(getOwnerId());
        }
    });

    requestMessage("Event.Draw", [this](const Kunlaboro::Message& msg)
    {
        if (!mTexture)
            return;

        auto& target = *std::get<0>(boost::any_cast<std::tuple<sf::RenderTarget*,float>>(msg.payload));

        sf::Sprite sprite(*mTexture);
        sprite.setOrigin((sf::Vector2f)mTexture->getSize() / 2.f);
        sprite.setPosition(mPosition);
        sprite.setRotation(mAngle * (180 / M_PI));

        if (mLifeTime > 6)
        {
            if ((int)(mLifeTime*2) % 2)
                sprite.setColor(sf::Color::Red);

            float perc = 1 - (mLifeTime-6)/4;
            sprite.setScale(perc, perc);
        }

        target.draw(sprite);
    });
    changeRequestPriority("Event.Draw", -1);

    requestComponent("Game.Weapon", [this](const Kunlaboro::Message& msg)
    {
        if (msg.type == Kunlaboro::Type_Create)
            mTexture = &dynamic_cast<Weapon*>(msg.sender)->weaponTexture();
        else
        {
            mTexture = nullptr;
            getEntitySystem()->destroyEntity(getOwnerId());
        }
    });

    requestMessage("Mr grabbyhands", [this](Kunlaboro::Message& msg)
    {
        auto pos = boost::any_cast<sf::Vector2f>(msg.payload);

        if (Math::distance(pos, mPosition) < 64)
        {
            msg.payload = true;
            msg.handled = true;
        }
    });

    requestMessage("I'm ending this!", [this](const Kunlaboro::Message& msg) { getEntitySystem()->destroyEntity(getOwnerId()); });
}
<commit_msg>Testing a possible fix for corruption<commit_after>#include "Pickup.hpp"
#include "Weapon.hpp"
#include "../Math.hpp"
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
#include <Kunlaboro/EntitySystem.hpp>
#include <random>
#include <cmath>

Pickup::Pickup() : Kunlaboro::Component("Game.Pickup"), mAngle(0), mTexture(nullptr), mLifeTime(0)
{
}

Pickup::~Pickup()
{
}

void Pickup::addedToEntity()
{
    {
        std::random_device dev;

        mAngle = std::uniform_real_distribution<float>(0, M_PI*2)(dev);
        mInertia = std::uniform_real_distribution<float>(64, 256)(dev);

        mStartAngle = mAngle;
    }

    requestMessage("Event.Update", [this](const Kunlaboro::Message& msg)
    {
        float dt = boost::any_cast<float>(msg.payload);

        if (mInertia > 0)
        {
            mPosition += sf::Vector2f(cos(mStartAngle), sin(mStartAngle)) * mInertia * dt;
            mAngle += mInertia * dt * (M_PI/180);
            mInertia -= dt * 100;
        }
        else
        {
            mLifeTime += dt;

            if (mLifeTime > 10)
                getEntitySystem()->destroyComponent(getEntitySystem()->getAllComponentsOnEntity(getOwnerId(), "Game.Weapon")[0]);
        }
    });

    requestMessage("Event.Draw", [this](const Kunlaboro::Message& msg)
    {
        if (!mTexture)
            return;

        auto& target = *std::get<0>(boost::any_cast<std::tuple<sf::RenderTarget*,float>>(msg.payload));

        sf::Sprite sprite(*mTexture);
        sprite.setOrigin((sf::Vector2f)mTexture->getSize() / 2.f);
        sprite.setPosition(mPosition);
        sprite.setRotation(mAngle * (180 / M_PI));

        if (mLifeTime > 6)
        {
            if ((int)(mLifeTime*2) % 2)
                sprite.setColor(sf::Color::Red);

            float perc = 1 - (mLifeTime-6)/4;
            sprite.setScale(perc, perc);
        }

        target.draw(sprite);
    });
    changeRequestPriority("Event.Draw", -1);

    requestComponent("Game.Weapon", [this](const Kunlaboro::Message& msg)
    {
        if (msg.type == Kunlaboro::Type_Create)
            mTexture = &dynamic_cast<Weapon*>(msg.sender)->weaponTexture();
        else
        {
            mTexture = nullptr;
            getEntitySystem()->destroyEntity(getOwnerId());
        }
    });

    requestMessage("Mr grabbyhands", [this](Kunlaboro::Message& msg)
    {
        auto pos = boost::any_cast<sf::Vector2f>(msg.payload);

        if (Math::distance(pos, mPosition) < 64)
        {
            msg.payload = true;
            msg.handled = true;
        }
    });

    requestMessage("I'm ending this!", [this](const Kunlaboro::Message& msg) { getEntitySystem()->destroyEntity(getOwnerId()); });
}
<|endoftext|>


<commit_before>#include <string>
#include <sstream>
#include <assert.h>

#include <iostream>

#include "fpconfig.hh"
#include "extrasrc/fptypes.hh"

#include "grammar.hh"
#include "opcodename.hh"

using namespace FPoptimizer_Grammar;
using namespace FUNCTIONPARSERTYPES;

const std::string FP_GetOpcodeName(FPoptimizer_Grammar::SpecialOpcode opcode, bool pad)
{
#if 1
    /* Symbolic meanings for the opcodes? */
    const char* p = 0;
    switch( opcode )
    {
        case NumConstant:   p = "NumConstant"; break;
        case ParamHolder:   p = "ParamHolder"; break;
        case SubFunction:   p = "SubFunction"; break;
    }
    std::ostringstream tmp;
    //if(!p) std::cerr << "o=" << opcode << "\n";
    assert(p);
    tmp << p;
    if(pad) while(tmp.str().size() < 12) tmp << ' ';
    return tmp.str();
#else
    /* Just numeric meanings */
    std::ostringstream tmp;
    tmp << opcode;
    if(pad) while(tmp.str().size() < 5) tmp << ' ';
    return tmp.str();
#endif
}

const std::string FP_GetOpcodeName(FUNCTIONPARSERTYPES::OPCODE opcode,        bool pad)
{
#if 1
    /* Symbolic meanings for the opcodes? */
    const char* p = 0;
    switch(opcode)
    {
        case cAbs: p = "cAbs"; break;
        case cAcos: p = "cAcos"; break;
        case cAcosh: p = "cAcosh"; break;
        case cArg: p = "cArg"; break;
        case cAsin: p = "cAsin"; break;
        case cAsinh: p = "cAsinh"; break;
        case cAtan: p = "cAtan"; break;
        case cAtan2: p = "cAtan2"; break;
        case cAtanh: p = "cAtanh"; break;
        case cCbrt: p = "cCbrt"; break;
        case cCeil: p = "cCeil"; break;
        case cConj: p = "cConj"; break;
        case cCos: p = "cCos"; break;
        case cCosh: p = "cCosh"; break;
        case cCot: p = "cCot"; break;
        case cCsc: p = "cCsc"; break;
        case cEval: p = "cEval"; break;
        case cExp: p = "cExp"; break;
        case cExp2: p = "cExp2"; break;
        case cFloor: p = "cFloor"; break;
        case cHypot: p = "cHypot"; break;
        case cIf: p = "cIf"; break;
        case cImag: p = "cImag"; break;
        case cInt: p = "cInt"; break;
        case cLog: p = "cLog"; break;
        case cLog2: p = "cLog2"; break;
        case cLog10: p = "cLog10"; break;
        case cMax: p = "cMax"; break;
        case cMin: p = "cMin"; break;
        case cPolar: p = "cPolar"; break;
        case cPow: p = "cPow"; break;
        case cReal: p = "cReal"; break;
        case cSec: p = "cSec"; break;
        case cSin: p = "cSin"; break;
        case cSinh: p = "cSinh"; break;
        case cSqrt: p = "cSqrt"; break;
        case cTan: p = "cTan"; break;
        case cTanh: p = "cTanh"; break;
        case cTrunc: p = "cTrunc"; break;
        case cImmed: p = "cImmed"; break;
        case cJump: p = "cJump"; break;
        case cNeg: p = "cNeg"; break;
        case cAdd: p = "cAdd"; break;
        case cSub: p = "cSub"; break;
        case cMul: p = "cMul"; break;
        case cDiv: p = "cDiv"; break;
        case cMod: p = "cMod"; break;
        case cEqual: p = "cEqual"; break;
        case cNEqual: p = "cNEqual"; break;
        case cLess: p = "cLess"; break;
        case cLessOrEq: p = "cLessOrEq"; break;
        case cGreater: p = "cGreater"; break;
        case cGreaterOrEq: p = "cGreaterOrEq"; break;
        case cNot: p = "cNot"; break;
        case cAnd: p = "cAnd"; break;
        case cOr: p = "cOr"; break;
        case cDeg: p = "cDeg"; break;
        case cRad: p = "cRad"; break;
        case cFCall: p = "cFCall"; break;
        case cPCall: p = "cPCall"; break;
#ifdef FP_SUPPORT_OPTIMIZER
        case cFetch: p = "cFetch"; break;
        case cPopNMov: p = "cPopNMov"; break;
        case cLog2by: p = "cLog2by"; break;
        case cNop: p = "cNop"; break;
#endif
        case cSinCos: p = "cSinCos"; break;
        case cSinhCosh: p = "cSinhCosh"; break;
        case cAbsNot: p = "cAbsNot"; break;
        case cAbsNotNot: p = "cAbsNotNot"; break;
        case cAbsAnd: p = "cAbsAnd"; break;
        case cAbsOr: p = "cAbsOr"; break;
        case cAbsIf: p = "cAbsIf"; break;
        case cDup: p = "cDup"; break;
        case cInv: p = "cInv"; break;
        case cSqr: p = "cSqr"; break;
        case cRDiv: p = "cRDiv"; break;
        case cRSub: p = "cRSub"; break;
        case cNotNot: p = "cNotNot"; break;
        case cRSqrt: p = "cRSqrt"; break;
        case VarBegin: p = "VarBegin"; break;
    }
    std::ostringstream tmp;
    //if(!p) std::cerr << "o=" << opcode << "\n";
    assert(p);
    tmp << p;
    if(pad) while(tmp.str().size() < 12) tmp << ' ';
    return tmp.str();
#else
    /* Just numeric meanings */
    std::ostringstream tmp;
    tmp << opcode;
    if(pad) while(tmp.str().size() < 5) tmp << ' ';
    return tmp.str();
#endif
}
<commit_msg>Handle cNop case, now that the enum is defined even when optimization is off.<commit_after>#include <string>
#include <sstream>
#include <assert.h>

#include <iostream>

#include "fpconfig.hh"
#include "extrasrc/fptypes.hh"

#include "grammar.hh"
#include "opcodename.hh"

using namespace FPoptimizer_Grammar;
using namespace FUNCTIONPARSERTYPES;

const std::string FP_GetOpcodeName(FPoptimizer_Grammar::SpecialOpcode opcode, bool pad)
{
#if 1
    /* Symbolic meanings for the opcodes? */
    const char* p = 0;
    switch( opcode )
    {
        case NumConstant:   p = "NumConstant"; break;
        case ParamHolder:   p = "ParamHolder"; break;
        case SubFunction:   p = "SubFunction"; break;
    }
    std::ostringstream tmp;
    //if(!p) std::cerr << "o=" << opcode << "\n";
    assert(p);
    tmp << p;
    if(pad) while(tmp.str().size() < 12) tmp << ' ';
    return tmp.str();
#else
    /* Just numeric meanings */
    std::ostringstream tmp;
    tmp << opcode;
    if(pad) while(tmp.str().size() < 5) tmp << ' ';
    return tmp.str();
#endif
}

const std::string FP_GetOpcodeName(FUNCTIONPARSERTYPES::OPCODE opcode,        bool pad)
{
#if 1
    /* Symbolic meanings for the opcodes? */
    const char* p = 0;
    switch(opcode)
    {
        case cAbs: p = "cAbs"; break;
        case cAcos: p = "cAcos"; break;
        case cAcosh: p = "cAcosh"; break;
        case cArg: p = "cArg"; break;
        case cAsin: p = "cAsin"; break;
        case cAsinh: p = "cAsinh"; break;
        case cAtan: p = "cAtan"; break;
        case cAtan2: p = "cAtan2"; break;
        case cAtanh: p = "cAtanh"; break;
        case cCbrt: p = "cCbrt"; break;
        case cCeil: p = "cCeil"; break;
        case cConj: p = "cConj"; break;
        case cCos: p = "cCos"; break;
        case cCosh: p = "cCosh"; break;
        case cCot: p = "cCot"; break;
        case cCsc: p = "cCsc"; break;
        case cEval: p = "cEval"; break;
        case cExp: p = "cExp"; break;
        case cExp2: p = "cExp2"; break;
        case cFloor: p = "cFloor"; break;
        case cHypot: p = "cHypot"; break;
        case cIf: p = "cIf"; break;
        case cImag: p = "cImag"; break;
        case cInt: p = "cInt"; break;
        case cLog: p = "cLog"; break;
        case cLog2: p = "cLog2"; break;
        case cLog10: p = "cLog10"; break;
        case cMax: p = "cMax"; break;
        case cMin: p = "cMin"; break;
        case cPolar: p = "cPolar"; break;
        case cPow: p = "cPow"; break;
        case cReal: p = "cReal"; break;
        case cSec: p = "cSec"; break;
        case cSin: p = "cSin"; break;
        case cSinh: p = "cSinh"; break;
        case cSqrt: p = "cSqrt"; break;
        case cTan: p = "cTan"; break;
        case cTanh: p = "cTanh"; break;
        case cTrunc: p = "cTrunc"; break;
        case cImmed: p = "cImmed"; break;
        case cJump: p = "cJump"; break;
        case cNeg: p = "cNeg"; break;
        case cAdd: p = "cAdd"; break;
        case cSub: p = "cSub"; break;
        case cMul: p = "cMul"; break;
        case cDiv: p = "cDiv"; break;
        case cMod: p = "cMod"; break;
        case cEqual: p = "cEqual"; break;
        case cNEqual: p = "cNEqual"; break;
        case cLess: p = "cLess"; break;
        case cLessOrEq: p = "cLessOrEq"; break;
        case cGreater: p = "cGreater"; break;
        case cGreaterOrEq: p = "cGreaterOrEq"; break;
        case cNot: p = "cNot"; break;
        case cAnd: p = "cAnd"; break;
        case cOr: p = "cOr"; break;
        case cDeg: p = "cDeg"; break;
        case cRad: p = "cRad"; break;
        case cFCall: p = "cFCall"; break;
        case cPCall: p = "cPCall"; break;
        case cFetch: p = "cFetch"; break;
#ifdef FP_SUPPORT_OPTIMIZER
        case cPopNMov: p = "cPopNMov"; break;
        case cLog2by: p = "cLog2by"; break;
#endif
        case cNop: p = "cNop"; break;
        case cSinCos: p = "cSinCos"; break;
        case cSinhCosh: p = "cSinhCosh"; break;
        case cAbsNot: p = "cAbsNot"; break;
        case cAbsNotNot: p = "cAbsNotNot"; break;
        case cAbsAnd: p = "cAbsAnd"; break;
        case cAbsOr: p = "cAbsOr"; break;
        case cAbsIf: p = "cAbsIf"; break;
        case cDup: p = "cDup"; break;
        case cInv: p = "cInv"; break;
        case cSqr: p = "cSqr"; break;
        case cRDiv: p = "cRDiv"; break;
        case cRSub: p = "cRSub"; break;
        case cNotNot: p = "cNotNot"; break;
        case cRSqrt: p = "cRSqrt"; break;
        case VarBegin: p = "VarBegin"; break;
    }
    std::ostringstream tmp;
    //if(!p) std::cerr << "o=" << opcode << "\n";
    assert(p);
    tmp << p;
    if(pad) while(tmp.str().size() < 12) tmp << ' ';
    return tmp.str();
#else
    /* Just numeric meanings */
    std::ostringstream tmp;
    tmp << opcode;
    if(pad) while(tmp.str().size() < 5) tmp << ' ';
    return tmp.str();
#endif
}
<|endoftext|>


<commit_before>#include "Hearthstone.h"

#include <QFile>
#include <QDesktopServices>
#include <QSettings>
#include <QTextStream>
#include <QRegExp>

#include <QJsonDocument>
#include <QJsonObject>

#ifdef Q_OS_MAC
#include "OSXWindowCapture.h"
#elif defined Q_OS_WIN
#include "WinWindowCapture.h"
#include "Shlobj.h"
#elif defined Q_OS_LINUX
#include <math.h>
#include "LinuxWindowCapture.h"
#endif

DEFINE_SINGLETON_SCOPE( Hearthstone );

Hearthstone::Hearthstone()
 : mCapture( NULL ), mGameRunning( false )
{
#ifdef Q_OS_MAC
    LOG("OS X host");
  mCapture = new OSXWindowCapture( WindowName() );
#elif defined Q_OS_WIN
    LOG("Windows host");
  mCapture = new WinWindowCapture( WindowName() );
#elif defined Q_OS_LINUX
 LOG("GNU/Linux host");
 mCapture = new LinuxWindowCapture ( WindowName() );
#endif

  // On OS X, WindowFound is quite CPU intensive
  // Starting time for HS is also long
  // So just check only once in a while
  mTimer = new QTimer( this );
  connect( mTimer, &QTimer::timeout, this, &Hearthstone::Update );
  mTimer->start( 5000 );
}

Hearthstone::~Hearthstone() {
  if( mCapture != NULL )
    delete mCapture;
}

void Hearthstone::Update() {
  bool isRunning = mCapture->WindowFound();

  if( mGameRunning != isRunning ) {
    mGameRunning = isRunning;

    if( isRunning ) {
      LOG( "Hearthstone is running" );
      emit GameStarted();
    } else {
      LOG( "Hearthstone stopped" );
      emit GameStopped();
    }
  }
}

QString Hearthstone::ReadAgentAttribute( const char *attributeName ) const {
    LOG("HS ReadAgentAttribute: %s", attributeName);
#ifdef Q_OS_MAC
  QString path = "/Users/Shared/Battle.net/Agent/agent.db";
#elif defined Q_OS_WIN
  wchar_t buffer[ MAX_PATH ];
  SHGetSpecialFolderPathW( NULL, buffer, CSIDL_COMMON_APPDATA, FALSE );
  QString programData = QString::fromWCharArray( buffer );
  QString path = programData + "\\Battle.net\\Agent\\agent.db";
#elif defined Q_OS_LINUX
  QString homeLocation = QStandardPaths::writableLocation( QStandardPaths::HomeLocation );
  QString path = homeLocation + "/.Hearthstone/agent.db";
  if(QFile(path).exists()){
    LOG("HS Agent DB file (agent.db): FOUND");
  }
  else{
      LOG("HS Agent DB file (agent.db): NOT FOUND");
  }
#endif

  QFile file( path );
  if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {
    DBG( "Couldn't open %s (%d)", qt2cstr( path ), file.error() );
    return "";
  }

  QString contents = file.readAll();
  QJsonDocument doc = QJsonDocument::fromJson( contents.toUtf8() );
  QJsonObject root = doc.object();

  QJsonObject hs = root["/game/hs_beta"].toObject()["resource"].toObject()["game"].toObject();
  return hs[ QString( attributeName ) ].toString();
}

bool Hearthstone::GameRunning() const {
  return mGameRunning;
}

#ifdef Q_OS_WIN
inline float roundf( float x ) {
   return x >= 0.0f ? floorf( x + 0.5f ) : ceilf( x - 0.5f );
}
#endif

bool Hearthstone::CaptureWholeScreen( QPixmap *screen ) {
  *screen = mCapture->Capture( 0, 0, Width(), Height() );
  return true;
}

QPixmap Hearthstone::Capture( int canvasWidth, int canvasHeight, int cx, int cy, int cw, int ch )
{
  UNUSED_ARG( canvasWidth );

  int x, y, w, h;

  int windowHeight = mCapture->Height();
  float scale = windowHeight / float( canvasHeight );

  x = roundf( cx * scale );
  y = roundf( cy * scale );

  w = roundf( cw * scale );
  h = roundf( ch * scale );

  return mCapture->Capture( x, y, w, h );
}

void Hearthstone::SetWindowCapture( WindowCapture *windowCapture ) {
  if( mCapture != NULL )
    delete mCapture;

  mCapture = windowCapture;
}

void Hearthstone::EnableLogging() {
  QString path = LogConfigPath();
  QFile file( path );

  bool logModified = false;

  // Read file contents
  QString contents;
  if( file.exists() ) {
    file.open( QIODevice::ReadOnly | QIODevice::Text );
    QTextStream in( &file );
    contents = in.readAll();
    file.close();
  }

  // Check what modules we have to activate
  QStringList modulesToActivate;
  for( int i = 0; i < NUM_LOG_MODULES; i++ ) {
    const char *moduleName = LOG_MODULE_NAMES[ i ];
    QString moduleLine = QString( "[%1]" ).arg( moduleName ) ;
    if( !contents.contains( moduleLine ) ) {
      contents += "\n";
      contents += moduleLine + "\n";
      contents += "LogLevel=1\n";
      contents += "FilePrinting=true\n";

      DBG( "Activate module %s", moduleName );
      logModified = true;
    }
  }

  QRegExp regexEnabledConsolePrinting( "ConsolePrinting\\s*=\\s*true",
      Qt::CaseInsensitive );
  QRegExp regexDisabledFilePrinting( "FilePrinting\\s*=\\s*false",
      Qt::CaseInsensitive );
  if( contents.contains( regexEnabledConsolePrinting ) ||
      contents.contains( regexDisabledFilePrinting ) )
  {
    contents.replace( regexEnabledConsolePrinting, "FilePrinting=true" );
    contents.replace( regexDisabledFilePrinting, "FilePrinting=true" );

    DBG( "FilePrinting enabled" );
    logModified = true;
  }

  // Finally write updated log.config
  if( logModified ) {
    DBG( "Log modified. Write new version" );

    if( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) {
      ERR( "Couldn't create file %s", qt2cstr( path ) );
    } else {
      QTextStream out( &file );
      out << contents;
    }
  }

  // Notify about restart if game is running
  Update();
  if( GameRunning() && logModified ) {
    emit GameRequiresRestart();
  }
}

void Hearthstone::DisableLogging() {
  QFile file( LogConfigPath() );
  if( file.exists() ) {
    file.remove();
    LOG( "Ingame log deactivated." );
  }
}

QString Hearthstone::LogConfigPath() const {
#ifdef Q_OS_MAC
  QString homeLocation = QStandardPaths::standardLocations( QStandardPaths::HomeLocation ).first();
  QString configPath = homeLocation + "/Library/Preferences/Blizzard/Hearthstone/log.config";
#elif defined Q_OS_WIN
  wchar_t buffer[ MAX_PATH ];
  SHGetSpecialFolderPathW( NULL, buffer, CSIDL_LOCAL_APPDATA, FALSE );
  QString localAppData = QString::fromWCharArray( buffer );
  QString configPath = localAppData + "/Blizzard/Hearthstone/log.config";
#elif defined Q_OS_LINUX
  QString homeLocation = QStandardPaths::writableLocation( QStandardPaths::HomeLocation );
  QString configPath = homeLocation + "/.Hearthstone/log.config";
#endif
  if(QFile(configPath).exists()){
      LOG("HS config file (log.config): FOUND");
  }
  else{
      LOG("HS config file (log.config): NOT FOUND");
  }
  return configPath;
}

QString Hearthstone::DetectHearthstonePath() const {
  static QString hsPath;

#ifdef Q_OS_LINUX
    QString homeLocation = QStandardPaths::writableLocation( QStandardPaths::HomeLocation );
    QString hsPathLnx = homeLocation + "/.Hearthstone";
    if( hsPathLnx.isEmpty() ) {
      ERR( "Hearthstone path not found" );
      return QString();
    }

<<<<<<< HEAD
    LOG("HS path: %s/Logs/", hsPathLnx.toStdString().c_str());
    return QString( "%1/Logs/" ).arg( hsPathLnx );
#elif Q_OS_WIN
    if( hsPath.isEmpty() ) {
        QString hsPathByAgent = ReadAgentAttribute( "install_dir" );
        QSettings hsKey( "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Hearthstone", QSettings::NativeFormat );
        QString hsPathByRegistry = hsKey.value( "InstallLocation" ).toString();

        if( hsPathByAgent.isEmpty() && hsPathByRegistry.isEmpty() ) {
            LOG( "Game folder not found. Fall back to default game path for now. You should set the path manually in the settings!" );
            hsPath = QString( getenv("PROGRAMFILES") ) + "/Hearthstone";
        } else if( !hsPathByRegistry.isEmpty() ) {
          hsPath = hsPathByRegistry;
        } else {
          hsPath = hsPathByAgent;
        }

        LOG( "Use Hearthstone location %s", qt2cstr( hsPath ) );
=======
    if( hsPathByAgent.isEmpty() && hsPathByRegistry.isEmpty() ) {
      LOG( "Game folder not found. Fall back to default game path for now. You should set the path manually in the settings!" );
      hsPath = QString( getenv("PROGRAMFILES") ) + "/Hearthstone";
    } else if( !hsPathByRegistry.isEmpty() ) {
      hsPath = hsPathByRegistry;
    } else {
      hsPath = hsPathByAgent;
>>>>>>> 62ff673c3064c35ac3106f5025bc079bdc1646e9
    }
#elif defined Q_OS_MAC
    if( hsPath.isEmpty() ) {
      LOG( "Fall back to default game path. You should set the path manually in the settings!" );
      hsPath = QStandardPaths::standardLocations( QStandardPaths::ApplicationsLocation ).first() + "/Hearthstone";
    }
#endif
<<<<<<< HEAD
=======
  }

>>>>>>> 62ff673c3064c35ac3106f5025bc079bdc1646e9
  return hsPath;
}

QString Hearthstone::WindowName() const {
  QString locale = ReadAgentAttribute( "selected_locale" );
  QString windowName = "Hearthstone";

#ifdef Q_OS_MAC
  // Under mac the window name is not localized
  return windowName;
#endif

  if( locale == "zhCN" ) {
    windowName = QString::fromWCharArray( L"炉石传说" );
  } else if( locale == "zhTW" ) {
    windowName = QString::fromWCharArray( L"《爐石戰記》" );
  } else if( locale == "koKR") {
    windowName = QString::fromWCharArray( L"하스스톤" );
  }

  return windowName;
}

int Hearthstone::Width() const {
  return mCapture->Width();
}

int Hearthstone::Height() const {
  return mCapture->Height();
}

<commit_msg>update travis build config<commit_after>#include "Hearthstone.h"

#include <QFile>
#include <QDesktopServices>
#include <QSettings>
#include <QTextStream>
#include <QRegExp>

#include <QJsonDocument>
#include <QJsonObject>

#ifdef Q_OS_MAC
#include "OSXWindowCapture.h"
#elif defined Q_OS_WIN
#include "WinWindowCapture.h"
#include "Shlobj.h"
#elif defined Q_OS_LINUX
#include <math.h>
#include "LinuxWindowCapture.h"
#endif

DEFINE_SINGLETON_SCOPE( Hearthstone );

Hearthstone::Hearthstone()
 : mCapture( NULL ), mGameRunning( false )
{
#ifdef Q_OS_MAC
    LOG("OS X host");
  mCapture = new OSXWindowCapture( WindowName() );
#elif defined Q_OS_WIN
    LOG("Windows host");
  mCapture = new WinWindowCapture( WindowName() );
#elif defined Q_OS_LINUX
 LOG("GNU/Linux host");
 mCapture = new LinuxWindowCapture ( WindowName() );
#endif

  // On OS X, WindowFound is quite CPU intensive
  // Starting time for HS is also long
  // So just check only once in a while
  mTimer = new QTimer( this );
  connect( mTimer, &QTimer::timeout, this, &Hearthstone::Update );
  mTimer->start( 5000 );
}

Hearthstone::~Hearthstone() {
  if( mCapture != NULL )
    delete mCapture;
}

void Hearthstone::Update() {
  bool isRunning = mCapture->WindowFound();

  if( mGameRunning != isRunning ) {
    mGameRunning = isRunning;

    if( isRunning ) {
      LOG( "Hearthstone is running" );
      emit GameStarted();
    } else {
      LOG( "Hearthstone stopped" );
      emit GameStopped();
    }
  }
}

QString Hearthstone::ReadAgentAttribute( const char *attributeName ) const {
    LOG("HS ReadAgentAttribute: %s", attributeName);
#ifdef Q_OS_MAC
  QString path = "/Users/Shared/Battle.net/Agent/agent.db";
#elif defined Q_OS_WIN
  wchar_t buffer[ MAX_PATH ];
  SHGetSpecialFolderPathW( NULL, buffer, CSIDL_COMMON_APPDATA, FALSE );
  QString programData = QString::fromWCharArray( buffer );
  QString path = programData + "\\Battle.net\\Agent\\agent.db";
#elif defined Q_OS_LINUX
  QString homeLocation = QStandardPaths::writableLocation( QStandardPaths::HomeLocation );
  QString path = homeLocation + "/.Hearthstone/agent.db";
  if(QFile(path).exists()){
    LOG("HS Agent DB file (agent.db): FOUND");
  }
  else{
      LOG("HS Agent DB file (agent.db): NOT FOUND");
  }
#endif

  QFile file( path );
  if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {
    DBG( "Couldn't open %s (%d)", qt2cstr( path ), file.error() );
    return "";
  }

  QString contents = file.readAll();
  QJsonDocument doc = QJsonDocument::fromJson( contents.toUtf8() );
  QJsonObject root = doc.object();

  QJsonObject hs = root["/game/hs_beta"].toObject()["resource"].toObject()["game"].toObject();
  return hs[ QString( attributeName ) ].toString();
}

bool Hearthstone::GameRunning() const {
  return mGameRunning;
}

#ifdef Q_OS_WIN
inline float roundf( float x ) {
   return x >= 0.0f ? floorf( x + 0.5f ) : ceilf( x - 0.5f );
}
#endif

bool Hearthstone::CaptureWholeScreen( QPixmap *screen ) {
  *screen = mCapture->Capture( 0, 0, Width(), Height() );
  return true;
}

QPixmap Hearthstone::Capture( int canvasWidth, int canvasHeight, int cx, int cy, int cw, int ch )
{
  UNUSED_ARG( canvasWidth );

  int x, y, w, h;

  int windowHeight = mCapture->Height();
  float scale = windowHeight / float( canvasHeight );

  x = roundf( cx * scale );
  y = roundf( cy * scale );

  w = roundf( cw * scale );
  h = roundf( ch * scale );

  return mCapture->Capture( x, y, w, h );
}

void Hearthstone::SetWindowCapture( WindowCapture *windowCapture ) {
  if( mCapture != NULL )
    delete mCapture;

  mCapture = windowCapture;
}

void Hearthstone::EnableLogging() {
  QString path = LogConfigPath();
  QFile file( path );

  bool logModified = false;

  // Read file contents
  QString contents;
  if( file.exists() ) {
    file.open( QIODevice::ReadOnly | QIODevice::Text );
    QTextStream in( &file );
    contents = in.readAll();
    file.close();
  }

  // Check what modules we have to activate
  QStringList modulesToActivate;
  for( int i = 0; i < NUM_LOG_MODULES; i++ ) {
    const char *moduleName = LOG_MODULE_NAMES[ i ];
    QString moduleLine = QString( "[%1]" ).arg( moduleName ) ;
    if( !contents.contains( moduleLine ) ) {
      contents += "\n";
      contents += moduleLine + "\n";
      contents += "LogLevel=1\n";
      contents += "FilePrinting=true\n";

      DBG( "Activate module %s", moduleName );
      logModified = true;
    }
  }

  QRegExp regexEnabledConsolePrinting( "ConsolePrinting\\s*=\\s*true",
      Qt::CaseInsensitive );
  QRegExp regexDisabledFilePrinting( "FilePrinting\\s*=\\s*false",
      Qt::CaseInsensitive );
  if( contents.contains( regexEnabledConsolePrinting ) ||
      contents.contains( regexDisabledFilePrinting ) )
  {
    contents.replace( regexEnabledConsolePrinting, "FilePrinting=true" );
    contents.replace( regexDisabledFilePrinting, "FilePrinting=true" );

    DBG( "FilePrinting enabled" );
    logModified = true;
  }

  // Finally write updated log.config
  if( logModified ) {
    DBG( "Log modified. Write new version" );

    if( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) {
      ERR( "Couldn't create file %s", qt2cstr( path ) );
    } else {
      QTextStream out( &file );
      out << contents;
    }
  }

  // Notify about restart if game is running
  Update();
  if( GameRunning() && logModified ) {
    emit GameRequiresRestart();
  }
}

void Hearthstone::DisableLogging() {
  QFile file( LogConfigPath() );
  if( file.exists() ) {
    file.remove();
    LOG( "Ingame log deactivated." );
  }
}

QString Hearthstone::LogConfigPath() const {
#ifdef Q_OS_MAC
  QString homeLocation = QStandardPaths::standardLocations( QStandardPaths::HomeLocation ).first();
  QString configPath = homeLocation + "/Library/Preferences/Blizzard/Hearthstone/log.config";
#elif defined Q_OS_WIN
  wchar_t buffer[ MAX_PATH ];
  SHGetSpecialFolderPathW( NULL, buffer, CSIDL_LOCAL_APPDATA, FALSE );
  QString localAppData = QString::fromWCharArray( buffer );
  QString configPath = localAppData + "/Blizzard/Hearthstone/log.config";
#elif defined Q_OS_LINUX
  QString homeLocation = QStandardPaths::writableLocation( QStandardPaths::HomeLocation );
  QString configPath = homeLocation + "/.Hearthstone/log.config";
#endif
  if(QFile(configPath).exists()){
      LOG("HS config file (log.config): FOUND");
  }
  else{
      LOG("HS config file (log.config): NOT FOUND");
  }
  return configPath;
}

QString Hearthstone::DetectHearthstonePath() const {
  static QString hsPath;

#ifdef Q_OS_LINUX
    QString homeLocation = QStandardPaths::writableLocation( QStandardPaths::HomeLocation );
    QString hsPathLnx = homeLocation + "/.Hearthstone";
    if( hsPathLnx.isEmpty() ) {
      ERR( "Hearthstone path not found" );
      return QString();
    }

    LOG("HS path: %s/Logs/", hsPathLnx.toStdString().c_str());
    return QString( "%1/Logs/" ).arg( hsPathLnx );
#elif Q_OS_WIN
    if( hsPath.isEmpty() ) {
        QString hsPathByAgent = ReadAgentAttribute( "install_dir" );
        QSettings hsKey( "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Hearthstone", QSettings::NativeFormat );
        QString hsPathByRegistry = hsKey.value( "InstallLocation" ).toString();

        if( hsPathByAgent.isEmpty() && hsPathByRegistry.isEmpty() ) {
            LOG( "Game folder not found. Fall back to default game path for now. You should set the path manually in the settings!" );
            hsPath = QString( getenv("PROGRAMFILES") ) + "/Hearthstone";
        } else if( !hsPathByRegistry.isEmpty() ) {
          hsPath = hsPathByRegistry;
        } else {
          hsPath = hsPathByAgent;
        }

        LOG( "Use Hearthstone location %s", qt2cstr( hsPath ) );
    }
#elif defined Q_OS_MAC
    if( hsPath.isEmpty() ) {
      LOG( "Fall back to default game path. You should set the path manually in the settings!" );
      hsPath = QStandardPaths::standardLocations( QStandardPaths::ApplicationsLocation ).first() + "/Hearthstone";
    }
#endif
  return hsPath;
}

QString Hearthstone::WindowName() const {
  QString locale = ReadAgentAttribute( "selected_locale" );
  QString windowName = "Hearthstone";

#ifdef Q_OS_MAC
  // Under mac the window name is not localized
  return windowName;
#endif

  if( locale == "zhCN" ) {
    windowName = QString::fromWCharArray( L"炉石传说" );
  } else if( locale == "zhTW" ) {
    windowName = QString::fromWCharArray( L"《爐石戰記》" );
  } else if( locale == "koKR") {
    windowName = QString::fromWCharArray( L"하스스톤" );
  }

  return windowName;
}

int Hearthstone::Width() const {
  return mCapture->Width();
}

int Hearthstone::Height() const {
  return mCapture->Height();
}

<|endoftext|>


<commit_before>// Copyright (C) 2010 - 2012 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

#include "CQPlayerControlWidget.h"

#include <QAction>
#include <QGridLayout>
#include <QIcon>
#include <QLayout>
#include <QPixmap>
#include <QPushButton>

#include <resourcesUI/CQIconResource.h>

QPushButton* createControl(const CQIconResource::IconID& iconId, int size = 32)
{
  QPushButton* button = new QPushButton;
  button->setFlat(true);
  button->setMinimumSize(size, size);
  button->setMaximumSize(size, size);
  button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  QIcon icon(CQIconResource::icon(iconId));
  button->setIcon(icon);
  button->setIconSize(QSize(size, size));
  return button;
}

CQPlayerControlWidget::CQPlayerControlWidget(QWidget* pParent)
  : QWidget(pParent)
  , mNumSteps(0)
  , mCurrentStep(0)
  , mPlaying(false)
{
  QGridLayout* pLayout = new QGridLayout;

  this->mpStepBackwardButton = createControl(CQIconResource::backward);
  pLayout->addWidget(this->mpStepBackwardButton, 0, 0, 1, 1);

  this->mpPlayButton = createControl(CQIconResource::play);
  pLayout->addWidget(this->mpPlayButton, 0, 1, 1, 1);

  this->mpStepForwardButton = createControl(CQIconResource::forward);
  pLayout->addWidget(this->mpStepForwardButton, 0, 2, 1, 1);

  this->mpBackwardButton = createControl(CQIconResource::skipBackward);
  pLayout->addWidget(this->mpBackwardButton, 1, 0, 1, 1);

  this->mpStopButton = createControl(CQIconResource::stop);
  pLayout->addWidget(this->mpStopButton, 1, 1, 1, 1);

  this->mpForwardButton = createControl(CQIconResource::skipForward);
  pLayout->addWidget(this->mpForwardButton, 1, 2, 1, 1);

  this->setLayout(pLayout);

  pLayout->setSizeConstraint(QLayout::SetFixedSize);

  this->createActions();

  this->updateButtons();
  this->updateActions();
  this->setTabOrder(this->mpPlayButton, this->mpStopButton);
  this->setTabOrder(this->mpStopButton, this->mpStepForwardButton);
  this->setTabOrder(this->mpStepForwardButton, this->mpStepBackwardButton);
  this->setTabOrder(this->mpStepBackwardButton, this->mpForwardButton);
  this->setTabOrder(this->mpForwardButton, this->mpBackwardButton);
  connect(this->mpPlayButton, SIGNAL(clicked()), this, SLOT(slot_play_clicked()));
  connect(this->mpStopButton, SIGNAL(clicked()), this, SLOT(slot_stop_clicked()));
  connect(this->mpForwardButton, SIGNAL(clicked()), this, SLOT(slot_forward_clicked()));
  connect(this->mpBackwardButton, SIGNAL(clicked()), this, SLOT(slot_backward_clicked()));
  connect(this->mpStepForwardButton, SIGNAL(clicked()), this, SLOT(slot_step_forward_clicked()));
  connect(this->mpStepBackwardButton, SIGNAL(clicked()), this, SLOT(slot_step_backward_clicked()));
}

void CQPlayerControlWidget::createActions()
{
  this->mpPlayAction = new QAction(CQIconResource::icon(CQIconResource::play), "play", this);
  connect(this->mpPlayAction, SIGNAL(triggered()), this, SLOT(slot_play_clicked()));
  this->mpPauseAction = new QAction(CQIconResource::icon(CQIconResource::pause), "pause", this);
  connect(this->mpPauseAction, SIGNAL(triggered()), this, SLOT(slot_pause_clicked()));
  this->mpStopAction = new QAction(CQIconResource::icon(CQIconResource::stop), "stop", this);
  connect(this->mpStopAction, SIGNAL(triggered()), this, SLOT(slot_stop_clicked()));
  this->mpForwardAction = new QAction(CQIconResource::icon(CQIconResource::skipForward), "forward", this);
  connect(this->mpForwardAction, SIGNAL(triggered()), this, SLOT(slot_forward_clicked()));
  this->mpBackwardAction = new QAction(CQIconResource::icon(CQIconResource::skipBackward), "backward", this);
  connect(this->mpBackwardAction, SIGNAL(triggered()), this, SLOT(slot_backward_clicked()));
  this->mpStepForwardAction = new QAction(CQIconResource::icon(CQIconResource::forward), "step forward", this);
  connect(this->mpStepForwardAction, SIGNAL(triggered()), this, SLOT(slot_step_forward_clicked()));
  this->mpStepBackwardAction = new QAction(CQIconResource::icon(CQIconResource::backward), "step backward", this);
  connect(this->mpStepBackwardAction, SIGNAL(triggered()), this, SLOT(slot_step_backward_clicked()));
}

void CQPlayerControlWidget::setNumSteps(size_t numSteps)
{
  this->mNumSteps = numSteps;
  this->updateButtons();
  this->updateActions();
}

void CQPlayerControlWidget::setCurrentStep(size_t currentStep)
{
  if (currentStep < this->mNumSteps)
    {
      this->mCurrentStep = currentStep;
    }
  else
    {
      this->mCurrentStep = this->mNumSteps - 1;
    }

  this->updateButtons();
  this->updateActions();
}

void CQPlayerControlWidget::slot_pause_clicked()
{
  this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::play));
  this->mPlaying = !this->mPlaying;
  this->mpPauseAction->setEnabled(FALSE);
  emit pause();
}

void CQPlayerControlWidget::slot_play_clicked()
{
  if (this->mPlaying)
    {
      this->slot_pause_clicked();
    }
  else
    {
      this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::pause));
      this->mPlaying = !this->mPlaying;
      this->mpPauseAction->setEnabled(TRUE);
      emit play();
    }
}

void CQPlayerControlWidget::slot_stop_clicked()
{
  this->mCurrentStep = 0;
  this->mPlaying = false;
  this->updateButtons();
  this->updateActions();
  emit stop();
}

void CQPlayerControlWidget::slot_forward_clicked()
{
  this->mCurrentStep = this->mNumSteps - 1;
  this->updateButtons();
  this->updateActions();
  emit forward();
}

void CQPlayerControlWidget::updateActions()
{
  if (this->mNumSteps < 2)
    {
      // disable all actionsw
      if (this->mpPlayAction->isEnabled())
        {
          this->mpPlayAction->setEnabled(FALSE);
        }

      if (this->mpPauseAction->isEnabled())
        {
          this->mpPauseAction->setEnabled(FALSE);
        }

      if (this->mpStopAction->isEnabled())
        {
          this->mpStopAction->setEnabled(FALSE);
        }

      if (this->mpForwardAction->isEnabled())
        {
          this->mpForwardAction->setEnabled(FALSE);
        }

      if (this->mpStepForwardAction->isEnabled())
        {
          this->mpStepForwardAction->setEnabled(FALSE);
        }

      if (this->mpBackwardAction->isEnabled())
        {
          this->mpBackwardAction->setEnabled(FALSE);
        }

      if (this->mpStepBackwardAction->isEnabled())
        {
          this->mpStepBackwardAction->setEnabled(FALSE);
        }
    }
  else
    {
      if (this->mCurrentStep == 0)
        {
          // make sure backward and step_backward are disabled and all other
          // actions are enabled
          if (!this->mPlaying)
            {
              this->mpPauseAction->setEnabled(FALSE);
            }
          else
            {
              this->mpPauseAction->setEnabled(TRUE);
            }

          if (this->mpBackwardAction->isEnabled())
            {
              this->mpBackwardAction->setEnabled(FALSE);
            }

          if (this->mpStepBackwardAction->isEnabled())
            {
              this->mpStepBackwardAction->setEnabled(FALSE);
            }

          if (this->mpPlayAction->isEnabled() == FALSE)
            {
              this->mpPlayAction->setEnabled(TRUE);
            }

          if (this->mpStopAction->isEnabled() == FALSE)
            {
              this->mpStopAction->setEnabled(TRUE);
            }

          if (this->mpForwardAction->isEnabled() == FALSE)
            {
              this->mpForwardAction->setEnabled(TRUE);
            }

          if (this->mpStepForwardAction->isEnabled() == FALSE)
            {
              this->mpStepForwardAction->setEnabled(TRUE);
            }
        }
      else if (this->mCurrentStep == this->mNumSteps - 1)
        {
          // make sure play, forward and step_forward are disabled and all other
          // actions are enabled
          // reset the icon on the play button
          if (this->mpForwardAction->isEnabled())
            {
              this->mpForwardAction->setEnabled(FALSE);
            }

          if (this->mpStepForwardAction->isEnabled())
            {
              this->mpStepForwardAction->setEnabled(FALSE);
            }

          if (this->mpPlayAction->isEnabled())
            {
              this->mpPlayAction->setEnabled(FALSE);
            }

          if (this->mpPauseAction->isEnabled())
            {
              this->mpPauseAction->setEnabled(FALSE);
            }

          if (this->mpBackwardAction->isEnabled() == FALSE)
            {
              this->mpBackwardAction->setEnabled(TRUE);
            }

          if (this->mpStepBackwardAction->isEnabled() == FALSE)
            {
              this->mpStepBackwardAction->setEnabled(TRUE);
            }

          if (this->mpStopAction->isEnabled() == FALSE)
            {
              this->mpStopAction->setEnabled(TRUE);
            }
        }
      else
        {
          // make sure all buttons are enabled
          if (this->mpPlayAction->isEnabled() == FALSE)
            {
              this->mpPlayAction->setEnabled(TRUE);
            }

          if (this->mpStopAction->isEnabled() == FALSE)
            {
              this->mpStopAction->setEnabled(TRUE);
            }

          if (this->mpForwardAction->isEnabled() == FALSE)
            {
              this->mpForwardAction->setEnabled(TRUE);
            }

          if (this->mpBackwardAction->isEnabled() == FALSE)
            {
              this->mpBackwardAction->setEnabled(TRUE);
            }

          if (this->mpStepBackwardAction->isEnabled() == FALSE)
            {
              this->mpStepBackwardAction->setEnabled(TRUE);
            }

          if (this->mpStepForwardAction->isEnabled() == FALSE)
            {
              this->mpStepForwardAction->setEnabled(TRUE);
            }
        }
    }
}

void CQPlayerControlWidget::updateButtons()
{
  if (this->mNumSteps < 2)
    {
      // disable all buttons
      if (this->mpPlayButton->isEnabled())
        {
          this->mpPlayButton->setEnabled(FALSE);

          if (this->mPlaying)
            {
              // reset the icon
              this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::play));
            }
        }

      if (this->mpStopButton->isEnabled())
        {
          this->mpStopButton->setEnabled(FALSE);
        }

      if (this->mpForwardButton->isEnabled())
        {
          this->mpForwardButton->setEnabled(FALSE);
        }

      if (this->mpStepForwardButton->isEnabled())
        {
          this->mpStepForwardButton->setEnabled(FALSE);
        }

      if (this->mpBackwardButton->isEnabled())
        {
          this->mpBackwardButton->setEnabled(FALSE);
        }

      if (this->mpStepBackwardButton->isEnabled())
        {
          this->mpStepBackwardButton->setEnabled(FALSE);
        }
    }
  else
    {
      if (this->mCurrentStep == 0)
        {
          // make sure backward and step_backward are disabled and all other
          // buttons are enabled
          if (!this->mPlaying)
            {
              this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::play));
            }
          else
            {
              this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::pause));
            }

          if (this->mpBackwardButton->isEnabled())
            {
              this->mpBackwardButton->setEnabled(FALSE);
            }

          if (this->mpStepBackwardButton->isEnabled())
            {
              this->mpStepBackwardButton->setEnabled(FALSE);
            }

          if (this->mpPlayButton->isEnabled() == FALSE)
            {
              this->mpPlayButton->setEnabled(TRUE);
            }

          if (this->mpStopButton->isEnabled() == FALSE)
            {
              this->mpStopButton->setEnabled(TRUE);
            }

          if (this->mpForwardButton->isEnabled() == FALSE)
            {
              this->mpForwardButton->setEnabled(TRUE);
            }

          if (this->mpStepForwardButton->isEnabled() == FALSE)
            {
              this->mpStepForwardButton->setEnabled(TRUE);
            }
        }
      else if (this->mCurrentStep == this->mNumSteps - 1)
        {
          // make sure play, forward and step_forward are disabled and all other
          // buttons are enabled
          // reset the icon on the play button
          if (this->mpForwardButton->isEnabled())
            {
              this->mpForwardButton->setEnabled(FALSE);
            }

          if (this->mpStepForwardButton->isEnabled())
            {
              this->mpStepForwardButton->setEnabled(FALSE);
            }

          if (this->mpPlayButton->isEnabled())
            {
              this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::play));
              this->mpPlayButton->setEnabled(FALSE);
            }

          if (this->mpBackwardButton->isEnabled() == FALSE)
            {
              this->mpBackwardButton->setEnabled(TRUE);
            }

          if (this->mpStepBackwardButton->isEnabled() == FALSE)
            {
              this->mpStepBackwardButton->setEnabled(TRUE);
            }

          if (this->mpStopButton->isEnabled() == FALSE)
            {
              this->mpStopButton->setEnabled(TRUE);
            }
        }
      else
        {
          // make sure all buttons are enabled
          if (this->mpPlayButton->isEnabled() == FALSE)
            {
              this->mpPlayButton->setEnabled(TRUE);
            }

          if (this->mpStopButton->isEnabled() == FALSE)
            {
              this->mpStopButton->setEnabled(TRUE);
            }

          if (this->mpForwardButton->isEnabled() == FALSE)
            {
              this->mpForwardButton->setEnabled(TRUE);
            }

          if (this->mpBackwardButton->isEnabled() == FALSE)
            {
              this->mpBackwardButton->setEnabled(TRUE);
            }

          if (this->mpStepBackwardButton->isEnabled() == FALSE)
            {
              this->mpStepBackwardButton->setEnabled(TRUE);
            }

          if (this->mpStepForwardButton->isEnabled() == FALSE)
            {
              this->mpStepForwardButton->setEnabled(TRUE);
            }
        }
    }
}

void CQPlayerControlWidget::slot_backward_clicked()
{
  this->mCurrentStep = 0;
  this->updateButtons();
  this->updateActions();
  emit backward();
}

void CQPlayerControlWidget::slot_step_forward_clicked()
{
  if (this->mCurrentStep != this->mNumSteps - 1)
    {
      ++this->mCurrentStep;
    }

  this->updateButtons();
  this->updateActions();
  emit step_forward();
}

void CQPlayerControlWidget::slot_step_backward_clicked()
{
  if (this->mCurrentStep != 0)
    {
      --this->mCurrentStep;
    }

  this->updateButtons();
  this->updateActions();
  emit step_backward();
}

bool CQPlayerControlWidget::isPlaying() const
{
  return this->mPlaying;
}

QAction* CQPlayerControlWidget::getPlayAction()
{
  return this->mpPlayAction;
}

QAction* CQPlayerControlWidget::getPauseAction()
{
  return this->mpPauseAction;
}

QAction* CQPlayerControlWidget::getStopAction()
{
  return this->mpStopAction;
}

QAction* CQPlayerControlWidget::getForwardAction()
{
  return this->mpForwardAction;
}

QAction* CQPlayerControlWidget::getBackwardAction()
{
  return this->mpBackwardAction;
}

QAction* CQPlayerControlWidget::getStepForwardAction()
{
  return this->mpStepForwardAction;
}

QAction* CQPlayerControlWidget::getStepBackwardAction()
{
  return this->mpStepBackwardAction;
}
<commit_msg>- fixed spelling<commit_after>// Copyright (C) 2010 - 2012 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

#include "CQPlayerControlWidget.h"

#include <QAction>
#include <QGridLayout>
#include <QIcon>
#include <QLayout>
#include <QPixmap>
#include <QPushButton>

#include <resourcesUI/CQIconResource.h>

QPushButton* createControl(const CQIconResource::IconID& iconId, int size = 32)
{
  QPushButton* button = new QPushButton;
  button->setFlat(true);
  button->setMinimumSize(size, size);
  button->setMaximumSize(size, size);
  button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  QIcon icon(CQIconResource::icon(iconId));
  button->setIcon(icon);
  button->setIconSize(QSize(size, size));
  return button;
}

CQPlayerControlWidget::CQPlayerControlWidget(QWidget* pParent)
  : QWidget(pParent)
  , mNumSteps(0)
  , mCurrentStep(0)
  , mPlaying(false)
{
  QGridLayout* pLayout = new QGridLayout;

  this->mpStepBackwardButton = createControl(CQIconResource::backward);
  pLayout->addWidget(this->mpStepBackwardButton, 0, 0, 1, 1);

  this->mpPlayButton = createControl(CQIconResource::play);
  pLayout->addWidget(this->mpPlayButton, 0, 1, 1, 1);

  this->mpStepForwardButton = createControl(CQIconResource::forward);
  pLayout->addWidget(this->mpStepForwardButton, 0, 2, 1, 1);

  this->mpBackwardButton = createControl(CQIconResource::skipBackward);
  pLayout->addWidget(this->mpBackwardButton, 1, 0, 1, 1);

  this->mpStopButton = createControl(CQIconResource::stop);
  pLayout->addWidget(this->mpStopButton, 1, 1, 1, 1);

  this->mpForwardButton = createControl(CQIconResource::skipForward);
  pLayout->addWidget(this->mpForwardButton, 1, 2, 1, 1);

  this->setLayout(pLayout);

  pLayout->setSizeConstraint(QLayout::SetFixedSize);

  this->createActions();

  this->updateButtons();
  this->updateActions();
  this->setTabOrder(this->mpPlayButton, this->mpStopButton);
  this->setTabOrder(this->mpStopButton, this->mpStepForwardButton);
  this->setTabOrder(this->mpStepForwardButton, this->mpStepBackwardButton);
  this->setTabOrder(this->mpStepBackwardButton, this->mpForwardButton);
  this->setTabOrder(this->mpForwardButton, this->mpBackwardButton);
  connect(this->mpPlayButton, SIGNAL(clicked()), this, SLOT(slot_play_clicked()));
  connect(this->mpStopButton, SIGNAL(clicked()), this, SLOT(slot_stop_clicked()));
  connect(this->mpForwardButton, SIGNAL(clicked()), this, SLOT(slot_forward_clicked()));
  connect(this->mpBackwardButton, SIGNAL(clicked()), this, SLOT(slot_backward_clicked()));
  connect(this->mpStepForwardButton, SIGNAL(clicked()), this, SLOT(slot_step_forward_clicked()));
  connect(this->mpStepBackwardButton, SIGNAL(clicked()), this, SLOT(slot_step_backward_clicked()));
}

void CQPlayerControlWidget::createActions()
{
  this->mpPlayAction = new QAction(CQIconResource::icon(CQIconResource::play), "Play", this);
  connect(this->mpPlayAction, SIGNAL(triggered()), this, SLOT(slot_play_clicked()));
  this->mpPauseAction = new QAction(CQIconResource::icon(CQIconResource::pause), "Pause", this);
  connect(this->mpPauseAction, SIGNAL(triggered()), this, SLOT(slot_pause_clicked()));
  this->mpStopAction = new QAction(CQIconResource::icon(CQIconResource::stop), "Stop", this);
  connect(this->mpStopAction, SIGNAL(triggered()), this, SLOT(slot_stop_clicked()));
  this->mpForwardAction = new QAction(CQIconResource::icon(CQIconResource::skipForward), "Forward", this);
  connect(this->mpForwardAction, SIGNAL(triggered()), this, SLOT(slot_forward_clicked()));
  this->mpBackwardAction = new QAction(CQIconResource::icon(CQIconResource::skipBackward), "Backward", this);
  connect(this->mpBackwardAction, SIGNAL(triggered()), this, SLOT(slot_backward_clicked()));
  this->mpStepForwardAction = new QAction(CQIconResource::icon(CQIconResource::forward), "Step Forward", this);
  connect(this->mpStepForwardAction, SIGNAL(triggered()), this, SLOT(slot_step_forward_clicked()));
  this->mpStepBackwardAction = new QAction(CQIconResource::icon(CQIconResource::backward), "Step Backward", this);
  connect(this->mpStepBackwardAction, SIGNAL(triggered()), this, SLOT(slot_step_backward_clicked()));
}

void CQPlayerControlWidget::setNumSteps(size_t numSteps)
{
  this->mNumSteps = numSteps;
  this->updateButtons();
  this->updateActions();
}

void CQPlayerControlWidget::setCurrentStep(size_t currentStep)
{
  if (currentStep < this->mNumSteps)
    {
      this->mCurrentStep = currentStep;
    }
  else
    {
      this->mCurrentStep = this->mNumSteps - 1;
    }

  this->updateButtons();
  this->updateActions();
}

void CQPlayerControlWidget::slot_pause_clicked()
{
  this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::play));
  this->mPlaying = !this->mPlaying;
  this->mpPauseAction->setEnabled(FALSE);
  emit pause();
}

void CQPlayerControlWidget::slot_play_clicked()
{
  if (this->mPlaying)
    {
      this->slot_pause_clicked();
    }
  else
    {
      this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::pause));
      this->mPlaying = !this->mPlaying;
      this->mpPauseAction->setEnabled(TRUE);
      emit play();
    }
}

void CQPlayerControlWidget::slot_stop_clicked()
{
  this->mCurrentStep = 0;
  this->mPlaying = false;
  this->updateButtons();
  this->updateActions();
  emit stop();
}

void CQPlayerControlWidget::slot_forward_clicked()
{
  this->mCurrentStep = this->mNumSteps - 1;
  this->updateButtons();
  this->updateActions();
  emit forward();
}

void CQPlayerControlWidget::updateActions()
{
  if (this->mNumSteps < 2)
    {
      // disable all actionsw
      if (this->mpPlayAction->isEnabled())
        {
          this->mpPlayAction->setEnabled(FALSE);
        }

      if (this->mpPauseAction->isEnabled())
        {
          this->mpPauseAction->setEnabled(FALSE);
        }

      if (this->mpStopAction->isEnabled())
        {
          this->mpStopAction->setEnabled(FALSE);
        }

      if (this->mpForwardAction->isEnabled())
        {
          this->mpForwardAction->setEnabled(FALSE);
        }

      if (this->mpStepForwardAction->isEnabled())
        {
          this->mpStepForwardAction->setEnabled(FALSE);
        }

      if (this->mpBackwardAction->isEnabled())
        {
          this->mpBackwardAction->setEnabled(FALSE);
        }

      if (this->mpStepBackwardAction->isEnabled())
        {
          this->mpStepBackwardAction->setEnabled(FALSE);
        }
    }
  else
    {
      if (this->mCurrentStep == 0)
        {
          // make sure backward and step_backward are disabled and all other
          // actions are enabled
          if (!this->mPlaying)
            {
              this->mpPauseAction->setEnabled(FALSE);
            }
          else
            {
              this->mpPauseAction->setEnabled(TRUE);
            }

          if (this->mpBackwardAction->isEnabled())
            {
              this->mpBackwardAction->setEnabled(FALSE);
            }

          if (this->mpStepBackwardAction->isEnabled())
            {
              this->mpStepBackwardAction->setEnabled(FALSE);
            }

          if (this->mpPlayAction->isEnabled() == FALSE)
            {
              this->mpPlayAction->setEnabled(TRUE);
            }

          if (this->mpStopAction->isEnabled() == FALSE)
            {
              this->mpStopAction->setEnabled(TRUE);
            }

          if (this->mpForwardAction->isEnabled() == FALSE)
            {
              this->mpForwardAction->setEnabled(TRUE);
            }

          if (this->mpStepForwardAction->isEnabled() == FALSE)
            {
              this->mpStepForwardAction->setEnabled(TRUE);
            }
        }
      else if (this->mCurrentStep == this->mNumSteps - 1)
        {
          // make sure play, forward and step_forward are disabled and all other
          // actions are enabled
          // reset the icon on the play button
          if (this->mpForwardAction->isEnabled())
            {
              this->mpForwardAction->setEnabled(FALSE);
            }

          if (this->mpStepForwardAction->isEnabled())
            {
              this->mpStepForwardAction->setEnabled(FALSE);
            }

          if (this->mpPlayAction->isEnabled())
            {
              this->mpPlayAction->setEnabled(FALSE);
            }

          if (this->mpPauseAction->isEnabled())
            {
              this->mpPauseAction->setEnabled(FALSE);
            }

          if (this->mpBackwardAction->isEnabled() == FALSE)
            {
              this->mpBackwardAction->setEnabled(TRUE);
            }

          if (this->mpStepBackwardAction->isEnabled() == FALSE)
            {
              this->mpStepBackwardAction->setEnabled(TRUE);
            }

          if (this->mpStopAction->isEnabled() == FALSE)
            {
              this->mpStopAction->setEnabled(TRUE);
            }
        }
      else
        {
          // make sure all buttons are enabled
          if (this->mpPlayAction->isEnabled() == FALSE)
            {
              this->mpPlayAction->setEnabled(TRUE);
            }

          if (this->mpStopAction->isEnabled() == FALSE)
            {
              this->mpStopAction->setEnabled(TRUE);
            }

          if (this->mpForwardAction->isEnabled() == FALSE)
            {
              this->mpForwardAction->setEnabled(TRUE);
            }

          if (this->mpBackwardAction->isEnabled() == FALSE)
            {
              this->mpBackwardAction->setEnabled(TRUE);
            }

          if (this->mpStepBackwardAction->isEnabled() == FALSE)
            {
              this->mpStepBackwardAction->setEnabled(TRUE);
            }

          if (this->mpStepForwardAction->isEnabled() == FALSE)
            {
              this->mpStepForwardAction->setEnabled(TRUE);
            }
        }
    }
}

void CQPlayerControlWidget::updateButtons()
{
  if (this->mNumSteps < 2)
    {
      // disable all buttons
      if (this->mpPlayButton->isEnabled())
        {
          this->mpPlayButton->setEnabled(FALSE);

          if (this->mPlaying)
            {
              // reset the icon
              this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::play));
            }
        }

      if (this->mpStopButton->isEnabled())
        {
          this->mpStopButton->setEnabled(FALSE);
        }

      if (this->mpForwardButton->isEnabled())
        {
          this->mpForwardButton->setEnabled(FALSE);
        }

      if (this->mpStepForwardButton->isEnabled())
        {
          this->mpStepForwardButton->setEnabled(FALSE);
        }

      if (this->mpBackwardButton->isEnabled())
        {
          this->mpBackwardButton->setEnabled(FALSE);
        }

      if (this->mpStepBackwardButton->isEnabled())
        {
          this->mpStepBackwardButton->setEnabled(FALSE);
        }
    }
  else
    {
      if (this->mCurrentStep == 0)
        {
          // make sure backward and step_backward are disabled and all other
          // buttons are enabled
          if (!this->mPlaying)
            {
              this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::play));
            }
          else
            {
              this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::pause));
            }

          if (this->mpBackwardButton->isEnabled())
            {
              this->mpBackwardButton->setEnabled(FALSE);
            }

          if (this->mpStepBackwardButton->isEnabled())
            {
              this->mpStepBackwardButton->setEnabled(FALSE);
            }

          if (this->mpPlayButton->isEnabled() == FALSE)
            {
              this->mpPlayButton->setEnabled(TRUE);
            }

          if (this->mpStopButton->isEnabled() == FALSE)
            {
              this->mpStopButton->setEnabled(TRUE);
            }

          if (this->mpForwardButton->isEnabled() == FALSE)
            {
              this->mpForwardButton->setEnabled(TRUE);
            }

          if (this->mpStepForwardButton->isEnabled() == FALSE)
            {
              this->mpStepForwardButton->setEnabled(TRUE);
            }
        }
      else if (this->mCurrentStep == this->mNumSteps - 1)
        {
          // make sure play, forward and step_forward are disabled and all other
          // buttons are enabled
          // reset the icon on the play button
          if (this->mpForwardButton->isEnabled())
            {
              this->mpForwardButton->setEnabled(FALSE);
            }

          if (this->mpStepForwardButton->isEnabled())
            {
              this->mpStepForwardButton->setEnabled(FALSE);
            }

          if (this->mpPlayButton->isEnabled())
            {
              this->mpPlayButton->setIcon(CQIconResource::icon(CQIconResource::play));
              this->mpPlayButton->setEnabled(FALSE);
            }

          if (this->mpBackwardButton->isEnabled() == FALSE)
            {
              this->mpBackwardButton->setEnabled(TRUE);
            }

          if (this->mpStepBackwardButton->isEnabled() == FALSE)
            {
              this->mpStepBackwardButton->setEnabled(TRUE);
            }

          if (this->mpStopButton->isEnabled() == FALSE)
            {
              this->mpStopButton->setEnabled(TRUE);
            }
        }
      else
        {
          // make sure all buttons are enabled
          if (this->mpPlayButton->isEnabled() == FALSE)
            {
              this->mpPlayButton->setEnabled(TRUE);
            }

          if (this->mpStopButton->isEnabled() == FALSE)
            {
              this->mpStopButton->setEnabled(TRUE);
            }

          if (this->mpForwardButton->isEnabled() == FALSE)
            {
              this->mpForwardButton->setEnabled(TRUE);
            }

          if (this->mpBackwardButton->isEnabled() == FALSE)
            {
              this->mpBackwardButton->setEnabled(TRUE);
            }

          if (this->mpStepBackwardButton->isEnabled() == FALSE)
            {
              this->mpStepBackwardButton->setEnabled(TRUE);
            }

          if (this->mpStepForwardButton->isEnabled() == FALSE)
            {
              this->mpStepForwardButton->setEnabled(TRUE);
            }
        }
    }
}

void CQPlayerControlWidget::slot_backward_clicked()
{
  this->mCurrentStep = 0;
  this->updateButtons();
  this->updateActions();
  emit backward();
}

void CQPlayerControlWidget::slot_step_forward_clicked()
{
  if (this->mCurrentStep != this->mNumSteps - 1)
    {
      ++this->mCurrentStep;
    }

  this->updateButtons();
  this->updateActions();
  emit step_forward();
}

void CQPlayerControlWidget::slot_step_backward_clicked()
{
  if (this->mCurrentStep != 0)
    {
      --this->mCurrentStep;
    }

  this->updateButtons();
  this->updateActions();
  emit step_backward();
}

bool CQPlayerControlWidget::isPlaying() const
{
  return this->mPlaying;
}

QAction* CQPlayerControlWidget::getPlayAction()
{
  return this->mpPlayAction;
}

QAction* CQPlayerControlWidget::getPauseAction()
{
  return this->mpPauseAction;
}

QAction* CQPlayerControlWidget::getStopAction()
{
  return this->mpStopAction;
}

QAction* CQPlayerControlWidget::getForwardAction()
{
  return this->mpForwardAction;
}

QAction* CQPlayerControlWidget::getBackwardAction()
{
  return this->mpBackwardAction;
}

QAction* CQPlayerControlWidget::getStepForwardAction()
{
  return this->mpStepForwardAction;
}

QAction* CQPlayerControlWidget::getStepBackwardAction()
{
  return this->mpStepBackwardAction;
}
<|endoftext|>