<commit_before>/***************************************************************************
 * This file have been borowed from the Ogre project
 * @LICENSE CHECK@
 ***************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include <CoreFoundation/CoreFoundation.h>
#include "macPlugins.h"
#include "CEGUILogger.h"

int main(void)
{
}

namespace CEGUI
{

     CFBundleRef mac_loadExeBundle(const char* name)
     {
          Logger* logger = Logger::getSingletonPtr();

          if(logger)
          {
               logger->logEvent("---- Beginning exe bundle loading ----");
               logger->logEvent(name);

               logger->logEvent("Get reference to base bundle", Insane);
          }
          CFBundleRef baseBundle = CFBundleGetBundleWithIdentifier(CFSTR("net.sourceforge.crayzedsgui.CEGUIBase"));

          if(logger) logger->logEvent("Get reference to main bundle", Insane);
          CFBundleRef mainBundle = CFBundleGetMainBundle();

          if(logger) logger->logEvent("Create name", Insane);
          CFStringRef nameRef = CFStringCreateWithCString(0, name, kCFStringEncodingASCII);
          CFURLRef bundleURL = 0; //URL of bundle to load
          CFBundleRef bundle = 0; //bundle to load

          // Cut off .bundle if present.
          if(logger) logger->logEvent("Check if .bundle suffix is on name", Insane);
          if(CFStringHasSuffix(nameRef, CFSTR(".bundle")))
          {
               if(logger) logger->logEvent("Create temporary name reference", Insane);
               CFStringRef nameTempRef = nameRef;
               int end = CFStringGetLength(nameTempRef) - CFStringGetLength(CFSTR(".bundle"));
               nameRef = CFStringCreateWithSubstring(0, nameTempRef, CFRangeMake(0, end));

               if(logger) logger->logEvent("Release temporary name reference", Insane);
               CFRelease(nameTempRef);
          }

          // Assume relative to Resources/ directory of application's bundle.
          if(logger) logger->logEvent("Create bundle URL", Insane);
          bundleURL = CFBundleCopyResourceURL(mainBundle, nameRef, CFSTR("bundle"), 0);
          if(bundleURL)
          {
               if(logger) logger->logEvent("Create bundle from URL", Insane);
               bundle = CFBundleCreate(0, bundleURL);

               if(logger) logger->logEvent("Release bundle URL", Insane);
               CFRelease(bundleURL);
          }

          // Otherwise, try Resources/ directory of CEGUI Framework bundle.
          if(!bundle)
          {
               if(logger) logger->logEvent("Couldn't get bundle from main bundle reference; try base");
               bundleURL = CFBundleCopyResourceURL(baseBundle, nameRef, CFSTR("bundle"), 0);
               if(bundleURL)
               {
                    if(logger) logger->logEvent("Create bundle from URL", Insane);
                    bundle = CFBundleCreate(0, bundleURL);

                    if(logger) logger->logEvent("Release bundle URL", Insane);
                    CFRelease(bundleURL);
               }
          }
          if(logger) logger->logEvent("Release name reference", Insane);
          CFRelease(nameRef);

          if(bundle)
          {
               if(logger) logger->logEvent("Load the bundle executable.", Insane);
               if(CFBundleLoadExecutable(bundle))
               {
                    if(logger) logger->logEvent("Bundle loaded successfully.");
                    return bundle;
               }
               else
               {
                    if(logger) logger->logEvent("Bundle loading failed!");
                    CFRelease(bundle);
               }
          }

          if(logger) logger->logEvent("Failure; return 0", Insane);
          return 0;
     }

     void* mac_getBundleSym(CFBundleRef bundle, const char* name)
     {
          Logger* logger = Logger::getSingletonPtr();

          if(logger) logger->logEvent("---- Getting bundle symbol ----", Insane);
          CFStringRef nameRef = CFStringCreateWithCString(0, name, kCFStringEncodingASCII);

          if(logger)
          {
               logger->logEvent("Find function pointer for name: ", Insane);
               logger->logEvent(name, Insane);
          }
          void* sym = CFBundleGetFunctionPointerForName(bundle, nameRef);

          if(logger) logger->logEvent("Release bundle name", Insane);
          CFRelease(nameRef);

          if(logger) logger->logEvent("---- Done getting bundle symbol ----", Insane);
          return sym;
     }

     // Returns 1 on error, 0 otherwise.
     bool mac_unloadExeBundle(CFBundleRef bundle)
     {
          Logger* logger = Logger::getSingletonPtr();

          if(logger) logger->logEvent("---- Beginning exe bundle unloading ----");

          if(bundle)
          {
               if(logger) logger->logEvent("Bundle unloaded.", Insane);

               // No-op, can't unload Obj-C bundles without crashing.
               return 0;
          }

          if(logger) logger->logEvent("---- Ending exe bundle unloading ----");
          return 1;
     }

     const char* mac_errorBundle()
     {
          return "Unknown Error";
     }

}
<commit_msg>MOD: Rewrote Mac bundle loading to look in 'PlugIns' locations instead of 'Resources' locations.<commit_after>/***************************************************************************
    This file was originally borowed from the Ogre project, though is now
    largely rewritten.
 ***************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2009 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include <CoreFoundation/CoreFoundation.h>
#include "macPlugins.h"
#include "CEGUILogger.h"

namespace CEGUI
{
//----------------------------------------------------------------------------//
CFStringRef createBundleNameString(const char* name)
{
    CFStringRef s = CFStringCreateWithCString(0, name, kCFStringEncodingASCII);

    if(!CFStringHasSuffix(s, CFSTR(".bundle")))
    {
        CFMutableStringRef ms = CFStringCreateMutableCopy(0, 0, s);
        CFRelease(s);
        CFStringAppend(ms, CFSTR(".bundle"));
        s = ms;
    }

    return s;
}

//----------------------------------------------------------------------------//
CFURLRef createFullPluginsURL(CFBundleRef bundle)
{
    CFURLRef pluginsURL = 0;

    CFURLRef baseURL = CFBundleCopyBundleURL(bundle);

    if (baseURL)
    {
        CFURLRef pluginsLocation = CFBundleCopyBuiltInPlugInsURL(bundle);

        if (pluginsLocation)
        {
            pluginsURL = CFURLCreateCopyAppendingPathComponent(0, baseURL,
                                              CFURLGetString(pluginsLocation),
                                              false);
            CFRelease(pluginsLocation);
        }

        CFRelease(baseURL);
    }

    return pluginsURL;
}

//----------------------------------------------------------------------------//
CFBundleRef createBundle(CFBundleRef sourceBundle, CFStringRef bundleName)
{
    CFBundleRef bundle = 0;

    CFURLRef pluginsURL = createFullPluginsURL(sourceBundle);

    if (pluginsURL)
    {
        CFURLRef bundleURL =
            CFURLCreateCopyAppendingPathComponent(0, pluginsURL,
                                                  bundleName, false);
        if (bundleURL)
        {
            bundle = CFBundleCreate(0, bundleURL);
            CFRelease(bundleURL);
        }

        CFRelease(pluginsURL);
    }

    return bundle;
}

//----------------------------------------------------------------------------//
CFBundleRef mac_loadExeBundle(const char* name)
{
    Logger* logger = Logger::getSingletonPtr();

    if (logger)
    {
       logger->logEvent("---- Beginning exe bundle loading ----");
       logger->logEvent("-- Input bundle name: " + String(name));
    }

    CFBundleRef bundle = 0;

    CFStringRef pluginName = createBundleNameString(name);

    if (pluginName)
    {
        bundle = createBundle(CFBundleGetMainBundle(), pluginName);

        if (!bundle)
        {
            if(logger)
                logger->logEvent(
                    "-- Couldn't get bundle from main app bundle reference; "
                    "trying CEGUIbase instead.");

            bundle =
                createBundle(CFBundleGetBundleWithIdentifier(
                                CFSTR("net.sourceforge.crayzedsgui.CEGUIBase")),
                             pluginName);
        }

        if (bundle)
        {
            if (!CFBundleLoadExecutable(bundle))
            {
                CFRelease(bundle);
                bundle = 0;
            }
        }

        CFRelease(pluginName);
    }

    if (logger)
    {
        if (bundle)
            logger->logEvent("-- Bundle loaded successfully.");
        else
            logger->logEvent("-- Bundle loading failed!");

        logger->logEvent("---- Finished exe bundle loading ----");
    }

    return bundle;
}

//----------------------------------------------------------------------------//
void* mac_getBundleSym(CFBundleRef bundle, const char* name)
{
    CFStringRef nameRef =
        CFStringCreateWithCString(0, name, kCFStringEncodingASCII);
    void* sym = CFBundleGetFunctionPointerForName(bundle, nameRef);
    CFRelease(nameRef);

    return sym;
}

//----------------------------------------------------------------------------//
// Returns 1 on error, 0 otherwise.
bool mac_unloadExeBundle(CFBundleRef bundle)
{
    if (bundle)
    {
        // No-op, can't unload Obj-C bundles without crashing.
        return 0;
    }

    return 1;
}

//----------------------------------------------------------------------------//
const char* mac_errorBundle()
{
    return "Unknown Error";
}

//----------------------------------------------------------------------------//

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: FormattedString.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: vg $ $Date: 2007-05-22 18:36:54 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef CHART_FORMATTEDSTRING_HXX
#define CHART_FORMATTEDSTRING_HXX

#ifndef CHART_MUTEXCONTAINER_HXX
#include "MutexContainer.hxx"
#endif
#ifndef CHART_OPROPERTYSET_HXX
#include "OPropertySet.hxx"
#endif

#ifndef _CPPUHELPER_IMPLBASE5_HXX_
#include <cppuhelper/implbase5.hxx>
#endif
#ifndef _COMPHELPER_UNO3_HXX_
#include <comphelper/uno3.hxx>
#endif
#include "ServiceMacros.hxx"
#include "ModifyListenerHelper.hxx"

#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_CHART2_XFORMATTEDSTRING_HPP_
#include <com/sun/star/chart2/XFormattedString.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XCLONEABLE_HPP_
#include <com/sun/star/util/XCloneable.hpp>
#endif

#ifndef _COM_SUN_STAR_UNO_XCOMPONENTCONTEXT_HPP_
#include <com/sun/star/uno/XComponentContext.hpp>
#endif

namespace chart
{

namespace impl
{
typedef ::cppu::WeakImplHelper5<
    ::com::sun::star::chart2::XFormattedString,
    ::com::sun::star::lang::XServiceInfo,
    ::com::sun::star::util::XCloneable,
    ::com::sun::star::util::XModifyBroadcaster,
    ::com::sun::star::util::XModifyListener >
    FormattedString_Base;
}

class FormattedString :
    public MutexContainer,
    public impl::FormattedString_Base,
    public ::property::OPropertySet
{
public:
    FormattedString( const ::rtl::OUString & rString );
    FormattedString( ::com::sun::star::uno::Reference<
           ::com::sun::star::uno::XComponentContext > const & xContext );
    virtual ~FormattedString();

    /// declare XServiceInfo methods
    APPHELPER_XSERVICEINFO_DECL()
    /// establish methods for factory instatiation
    APPHELPER_SERVICE_FACTORY_HELPER( FormattedString )

    /// merge XInterface implementations
     DECLARE_XINTERFACE()
    /// merge XTypeProvider implementations
     DECLARE_XTYPEPROVIDER()

protected:
    explicit FormattedString( const FormattedString & rOther );

    // ____ XFormattedString ____
    virtual ::rtl::OUString SAL_CALL getString()
        throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL setString( const ::rtl::OUString& String )
        throw (::com::sun::star::uno::RuntimeException);

    // ____ OPropertySet ____
    virtual ::com::sun::star::uno::Any GetDefaultValue( sal_Int32 nHandle ) const
        throw(::com::sun::star::beans::UnknownPropertyException);

    // ____ OPropertySet ____
    virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper();

    // ____ XPropertySet ____
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL
        getPropertySetInfo()
        throw (::com::sun::star::uno::RuntimeException);

//  virtual sal_Bool SAL_CALL convertFastPropertyValue
//         ( ::com::sun::star::uno::Any & rConvertedValue,
//           ::com::sun::star::uno::Any & rOldValue,
//           sal_Int32 nHandle,
//           const ::com::sun::star::uno::Any& rValue )
//      throw (::com::sun::star::lang::IllegalArgumentException);

    // ____ XCloneable ____
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloneable > SAL_CALL createClone()
        throw (::com::sun::star::uno::RuntimeException);

    // ____ XModifyBroadcaster ____
    virtual void SAL_CALL addModifyListener(
        const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener >& aListener )
        throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeModifyListener(
        const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener >& aListener )
        throw (::com::sun::star::uno::RuntimeException);

    // ____ XModifyListener ____
    virtual void SAL_CALL modified(
        const ::com::sun::star::lang::EventObject& aEvent )
        throw (::com::sun::star::uno::RuntimeException);

    // ____ XEventListener (base of XModifyListener) ____
    virtual void SAL_CALL disposing(
        const ::com::sun::star::lang::EventObject& Source )
        throw (::com::sun::star::uno::RuntimeException);

    // ____ OPropertySet ____
    virtual void firePropertyChangeEvent();

    void fireModifyEvent();

private:
    ::rtl::OUString m_aString;

    ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener > m_xModifyEventForwarder;
};

} //  namespace chart

// CHART_FORMATTEDSTRING_HXX
#endif
<commit_msg>INTEGRATION: CWS chart11 (1.4.38); FILE MERGED 2007/07/31 22:19:25 bm 1.4.38.1: #i79522# warnings on Solaris removed<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: FormattedString.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: vg $ $Date: 2007-09-18 15:01:26 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef CHART_FORMATTEDSTRING_HXX
#define CHART_FORMATTEDSTRING_HXX

#ifndef CHART_MUTEXCONTAINER_HXX
#include "MutexContainer.hxx"
#endif
#ifndef CHART_OPROPERTYSET_HXX
#include "OPropertySet.hxx"
#endif

#ifndef _CPPUHELPER_IMPLBASE5_HXX_
#include <cppuhelper/implbase5.hxx>
#endif
#ifndef _COMPHELPER_UNO3_HXX_
#include <comphelper/uno3.hxx>
#endif
#include "ServiceMacros.hxx"
#include "ModifyListenerHelper.hxx"

#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_CHART2_XFORMATTEDSTRING_HPP_
#include <com/sun/star/chart2/XFormattedString.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XCLONEABLE_HPP_
#include <com/sun/star/util/XCloneable.hpp>
#endif

#ifndef _COM_SUN_STAR_UNO_XCOMPONENTCONTEXT_HPP_
#include <com/sun/star/uno/XComponentContext.hpp>
#endif

namespace chart
{

namespace impl
{
typedef ::cppu::WeakImplHelper5<
    ::com::sun::star::chart2::XFormattedString,
    ::com::sun::star::lang::XServiceInfo,
    ::com::sun::star::util::XCloneable,
    ::com::sun::star::util::XModifyBroadcaster,
    ::com::sun::star::util::XModifyListener >
    FormattedString_Base;
}

class FormattedString :
    public MutexContainer,
    public impl::FormattedString_Base,
    public ::property::OPropertySet
{
public:
    FormattedString( const ::rtl::OUString & rString );
    FormattedString( ::com::sun::star::uno::Reference<
           ::com::sun::star::uno::XComponentContext > const & xContext );
    virtual ~FormattedString();

    /// declare XServiceInfo methods
    APPHELPER_XSERVICEINFO_DECL()
    /// establish methods for factory instatiation
    APPHELPER_SERVICE_FACTORY_HELPER( FormattedString )

    /// merge XInterface implementations
     DECLARE_XINTERFACE()
    /// merge XTypeProvider implementations
     DECLARE_XTYPEPROVIDER()

protected:
    explicit FormattedString( const FormattedString & rOther );

    // ____ XFormattedString ____
    virtual ::rtl::OUString SAL_CALL getString()
        throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL setString( const ::rtl::OUString& String )
        throw (::com::sun::star::uno::RuntimeException);

    // ____ OPropertySet ____
    virtual ::com::sun::star::uno::Any GetDefaultValue( sal_Int32 nHandle ) const
        throw(::com::sun::star::beans::UnknownPropertyException);

    // ____ OPropertySet ____
    virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper();

    // ____ XPropertySet ____
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL
        getPropertySetInfo()
        throw (::com::sun::star::uno::RuntimeException);

//  virtual sal_Bool SAL_CALL convertFastPropertyValue
//         ( ::com::sun::star::uno::Any & rConvertedValue,
//           ::com::sun::star::uno::Any & rOldValue,
//           sal_Int32 nHandle,
//           const ::com::sun::star::uno::Any& rValue )
//      throw (::com::sun::star::lang::IllegalArgumentException);

    // ____ XCloneable ____
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloneable > SAL_CALL createClone()
        throw (::com::sun::star::uno::RuntimeException);

    // ____ XModifyBroadcaster ____
    virtual void SAL_CALL addModifyListener(
        const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener >& aListener )
        throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeModifyListener(
        const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener >& aListener )
        throw (::com::sun::star::uno::RuntimeException);

    // ____ XModifyListener ____
    virtual void SAL_CALL modified(
        const ::com::sun::star::lang::EventObject& aEvent )
        throw (::com::sun::star::uno::RuntimeException);

    // ____ XEventListener (base of XModifyListener) ____
    virtual void SAL_CALL disposing(
        const ::com::sun::star::lang::EventObject& Source )
        throw (::com::sun::star::uno::RuntimeException);

    // ____ OPropertySet ____
    virtual void firePropertyChangeEvent();
    using OPropertySet::disposing;

    void fireModifyEvent();

private:
    ::rtl::OUString m_aString;

    ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener > m_xModifyEventForwarder;
};

} //  namespace chart

// CHART_FORMATTEDSTRING_HXX
#endif
<|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/chromeos/audio_mixer_pulse.h"

#include <pulse/pulseaudio.h>

#include "base/logging.h"
#include "base/message_loop.h"
#include "base/task.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/browser_thread.h"

namespace chromeos {

// Using asynchronous versions of the threaded PulseAudio API, as well
// as a worker thread so gets, sets, and the init sequence do not block the
// calling thread.  GetVolume() and IsMute() can still be called synchronously
// if needed, but take a bit longer (~2ms vs ~0.3ms).
//
// Set calls just return without waiting.  If you must guarantee the value has
// been set before continuing, immediately call the blocking Get version to
// synchronously get the value back.
//
// TODO(davej): Serialize volume/mute to preserve settings when restarting?

namespace {

const int kInvalidDeviceId = -1;

const double kMinVolumeDb = -90.0;
// Choosing 6.0dB here instead of 0dB to give user chance to amplify audio some
// in case sounds or their setup is too quiet for them.
const double kMaxVolumeDb = 6.0;

// Used for passing custom data to the PulseAudio callbacks.
struct CallbackWrapper {
  AudioMixerPulse* instance;
  bool done;
  void* userdata;
};

}  // namespace

// AudioInfo contains all the values we care about when getting info for a
// Sink (output device) used by GetAudioInfo().
struct AudioMixerPulse::AudioInfo {
  pa_cvolume cvolume;
  bool muted;
};

AudioMixerPulse::AudioMixerPulse()
    : device_id_(kInvalidDeviceId),
      last_channels_(0),
      mainloop_lock_count_(0),
      mixer_state_(UNINITIALIZED),
      pa_context_(NULL),
      pa_mainloop_(NULL) {
}

AudioMixerPulse::~AudioMixerPulse() {
  PulseAudioFree();
  if (thread_ != NULL) {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    // A ScopedAllowIO object is required to join the thread when calling Stop.
    // The worker thread should be idle at this time.
    // See http://crosbug.com/11110 for discussion.
    base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
    thread_->message_loop()->AssertIdle();

    thread_->Stop();
    thread_.reset();
  }
}

void AudioMixerPulse::Init(InitDoneCallback* callback) {
  DCHECK(callback);
  if (!InitThread()) {
    callback->Run(false);
    delete callback;
    return;
  }

  // Post the task of starting up, which can block for 200-500ms,
  // so best not to do it on the caller's thread.
  thread_->message_loop()->PostTask(FROM_HERE,
      NewRunnableMethod(this, &AudioMixerPulse::DoInit, callback));
}

bool AudioMixerPulse::InitSync() {
  if (!InitThread())
    return false;
  return PulseAudioInit();
}

double AudioMixerPulse::GetVolumeDb() const {
  if (!MainloopLockIfReady())
    return AudioMixer::kSilenceDb;
  AudioInfo data;
  GetAudioInfo(&data);
  MainloopUnlock();
  return pa_sw_volume_to_dB(data.cvolume.values[0]);
}

bool AudioMixerPulse::GetVolumeLimits(double* vol_min, double* vol_max) {
  if (vol_min)
    *vol_min = kMinVolumeDb;
  if (vol_max)
    *vol_max = kMaxVolumeDb;
  return true;
}

void AudioMixerPulse::SetVolumeDb(double vol_db) {
  if (!MainloopLockIfReady())
    return;

  // last_channels_ determines the number of channels on the main output device,
  // and is used later to set the volume on all channels at once.
  if (!last_channels_) {
    AudioInfo data;
    GetAudioInfo(&data);
    last_channels_ = data.cvolume.channels;
  }

  pa_operation* pa_op;
  pa_cvolume cvolume;
  pa_cvolume_set(&cvolume, last_channels_, pa_sw_volume_from_dB(vol_db));
  pa_op = pa_context_set_sink_volume_by_index(pa_context_, device_id_,
                                              &cvolume, NULL, NULL);
  pa_operation_unref(pa_op);
  MainloopUnlock();
  VLOG(1) << "Set volume to " << vol_db << " dB";
}

bool AudioMixerPulse::IsMute() const {
  if (!MainloopLockIfReady())
    return false;
  AudioInfo data;
  GetAudioInfo(&data);
  MainloopUnlock();
  return data.muted;
}

void AudioMixerPulse::SetMute(bool mute) {
  if (!MainloopLockIfReady())
    return;
  pa_operation* pa_op;
  pa_op = pa_context_set_sink_mute_by_index(pa_context_, device_id_,
                                            mute ? 1 : 0, NULL, NULL);
  pa_operation_unref(pa_op);
  MainloopUnlock();
  VLOG(1) << "Set mute to " << mute;
}

AudioMixer::State AudioMixerPulse::GetState() const {
  base::AutoLock lock(mixer_state_lock_);
  // If we think it's ready, verify it is actually so.
  if ((mixer_state_ == READY) &&
      (pa_context_get_state(pa_context_) != PA_CONTEXT_READY))
    mixer_state_ = IN_ERROR;
  return mixer_state_;
}

////////////////////////////////////////////////////////////////////////////////
// Private functions follow

void AudioMixerPulse::DoInit(InitDoneCallback* callback) {
  bool success = PulseAudioInit();
  callback->Run(success);
  delete callback;
}

bool AudioMixerPulse::InitThread() {
  base::AutoLock lock(mixer_state_lock_);

  if (mixer_state_ != UNINITIALIZED)
    return false;

  if (thread_ == NULL) {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    thread_.reset(new base::Thread("AudioMixerPulse"));
    if (!thread_->Start()) {
      thread_.reset();
      return false;
    }
  }
  mixer_state_ = INITIALIZING;
  return true;
}

// static
void AudioMixerPulse::ConnectToPulseCallbackThunk(
    pa_context* context, void* userdata) {
  CallbackWrapper* data =
      static_cast<CallbackWrapper*>(userdata);
  data->instance->OnConnectToPulseCallback(context, &data->done);
}

void AudioMixerPulse::OnConnectToPulseCallback(
    pa_context* context, bool* connect_done) {
  pa_context_state_t state = pa_context_get_state(context);
  if (state == PA_CONTEXT_READY ||
      state == PA_CONTEXT_FAILED ||
      state == PA_CONTEXT_TERMINATED) {
    // Connection process has reached a terminal state. Wake PulseAudioInit().
    *connect_done = true;
    MainloopSignal();
  }
}

bool AudioMixerPulse::PulseAudioInit() {
  pa_context_state_t state = PA_CONTEXT_FAILED;

  {
    base::AutoLock lock(mixer_state_lock_);
    if (mixer_state_ != INITIALIZING)
      return false;

    pa_mainloop_ = pa_threaded_mainloop_new();
    if (!pa_mainloop_) {
      LOG(ERROR) << "Can't create PulseAudio mainloop";
      mixer_state_ = UNINITIALIZED;
      return false;
    }

    if (pa_threaded_mainloop_start(pa_mainloop_) != 0) {
      LOG(ERROR) << "Can't start PulseAudio mainloop";
      pa_threaded_mainloop_free(pa_mainloop_);
      mixer_state_ = UNINITIALIZED;
      return false;
    }
  }

  while (true) {
    // Create connection to default server.
    if (!MainloopSafeLock())
      return false;

    while (true) {
      pa_mainloop_api* pa_mlapi = pa_threaded_mainloop_get_api(pa_mainloop_);
      if (!pa_mlapi) {
        LOG(ERROR) << "Can't get PulseAudio mainloop api";
        break;
      }
      // This one takes the most time if run at app startup.
      pa_context_ = pa_context_new(pa_mlapi, "ChromeAudio");
      if (!pa_context_) {
        LOG(ERROR) << "Can't create new PulseAudio context";
        break;
      }

      MainloopUnlock();
      if (!MainloopSafeLock())
        return false;

      CallbackWrapper data = {this, false, NULL};
      pa_context_set_state_callback(pa_context_,
                                    &ConnectToPulseCallbackThunk,
                                    &data);

      if (pa_context_connect(pa_context_, NULL,
                             PA_CONTEXT_NOAUTOSPAWN, NULL) != 0) {
        LOG(ERROR) << "Can't start connection to PulseAudio sound server";
      } else {
        // Wait until we have a completed connection or fail.
        do {
          MainloopWait();
        } while (!data.done);

        state = pa_context_get_state(pa_context_);

        if (state == PA_CONTEXT_FAILED) {
          LOG(ERROR) << "PulseAudio connection failed (daemon not running?)";
        } else if (state == PA_CONTEXT_TERMINATED) {
          LOG(ERROR) << "PulseAudio connection terminated early";
        } else if (state != PA_CONTEXT_READY) {
          LOG(ERROR) << "Unknown problem connecting to PulseAudio";
        }
      }

      pa_context_set_state_callback(pa_context_, NULL, NULL);
      break;
    }

    MainloopUnlock();

    if (state != PA_CONTEXT_READY)
      break;

    if (!MainloopSafeLock())
      return false;
    GetDefaultPlaybackDevice();
    MainloopUnlock();

    if (device_id_ == kInvalidDeviceId)
      break;

    {
      base::AutoLock lock(mixer_state_lock_);
      if (mixer_state_ == SHUTTING_DOWN)
        return false;
      mixer_state_ = READY;
    }

    return true;
  }

  // Failed startup sequence, clean up now.
  PulseAudioFree();
  return false;
}

void AudioMixerPulse::PulseAudioFree() {
  {
    base::AutoLock lock(mixer_state_lock_);
    if (!pa_mainloop_)
      mixer_state_ = UNINITIALIZED;
    if ((mixer_state_ == UNINITIALIZED) || (mixer_state_ == SHUTTING_DOWN))
      return;

    // If still initializing on another thread, this will cause it to exit.
    mixer_state_ = SHUTTING_DOWN;
  }

  DCHECK(pa_mainloop_);

  MainloopLock();
  if (pa_context_) {
    pa_context_disconnect(pa_context_);
    pa_context_unref(pa_context_);
    pa_context_ = NULL;
  }
  MainloopUnlock();

  pa_threaded_mainloop_stop(pa_mainloop_);
  pa_threaded_mainloop_free(pa_mainloop_);
  pa_mainloop_ = NULL;

  {
    base::AutoLock lock(mixer_state_lock_);
    mixer_state_ = UNINITIALIZED;
  }
}

void AudioMixerPulse::CompleteOperation(pa_operation* pa_op,
                                        bool* done) const {
  // After starting any operation, this helper checks if it started OK, then
  // waits for it to complete by iterating through the mainloop until the
  // operation is not running anymore.
  CHECK(pa_op);

  while (pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING) {
    // If operation still running, but we got what we needed, cancel it now.
    if (*done) {
      pa_operation_cancel(pa_op);
      break;
    }
    MainloopWait();
  }
  pa_operation_unref(pa_op);
}

// Must be called with mainloop lock held
void AudioMixerPulse::GetDefaultPlaybackDevice() {
  DCHECK_GT(mainloop_lock_count_, 0);
  DCHECK(pa_context_);
  DCHECK(pa_context_get_state(pa_context_) == PA_CONTEXT_READY);

  CallbackWrapper data = {this, false, NULL};

  pa_operation* pa_op = pa_context_get_sink_info_list(pa_context_,
                                        EnumerateDevicesCallback,
                                        &data);
  CompleteOperation(pa_op, &data.done);
  return;
}

void AudioMixerPulse::OnEnumerateDevices(const pa_sink_info* sink_info,
                                         int eol, bool* done) {
  if (device_id_ != kInvalidDeviceId)
    return;

  // TODO(davej): Should we handle cases of more than one output sink device?

  // eol is < 0 for error, > 0 for end of list, ==0 while listing.
  if (eol == 0) {
    device_id_ = sink_info->index;
  }
  *done = true;
  MainloopSignal();
}

// static
void AudioMixerPulse::EnumerateDevicesCallback(pa_context* unused,
                                               const pa_sink_info* sink_info,
                                               int eol,
                                               void* userdata) {
  CallbackWrapper* data =
      static_cast<CallbackWrapper*>(userdata);
  data->instance->OnEnumerateDevices(sink_info, eol, &data->done);
}

// Must be called with lock held
void AudioMixerPulse::GetAudioInfo(AudioInfo* info) const {
  DCHECK_GT(mainloop_lock_count_, 0);
  CallbackWrapper data = {const_cast<AudioMixerPulse*>(this), false, info};
  pa_operation* pa_op = pa_context_get_sink_info_by_index(pa_context_,
                                                          device_id_,
                                                          GetAudioInfoCallback,
                                                          &data);
  CompleteOperation(pa_op, &data.done);
}

// static
void AudioMixerPulse::GetAudioInfoCallback(pa_context* unused,
                                           const pa_sink_info* sink_info,
                                           int eol,
                                           void* userdata) {
  CallbackWrapper* data = static_cast<CallbackWrapper*>(userdata);
  AudioInfo* info = static_cast<AudioInfo*>(data->userdata);

  // Copy just the information we care about.
  if (eol == 0) {
    info->cvolume = sink_info->volume;
    info->muted = sink_info->mute ? true : false;
    data->done = true;
  }
  data->instance->MainloopSignal();
}

inline void AudioMixerPulse::MainloopLock() const {
  pa_threaded_mainloop_lock(pa_mainloop_);
  ++mainloop_lock_count_;
}

inline void AudioMixerPulse::MainloopUnlock() const {
  --mainloop_lock_count_;
  pa_threaded_mainloop_unlock(pa_mainloop_);
}

// Must be called with the lock held.
inline void AudioMixerPulse::MainloopWait() const {
  DCHECK_GT(mainloop_lock_count_, 0);
  pa_threaded_mainloop_wait(pa_mainloop_);
}

// Must be called with the lock held.
inline void AudioMixerPulse::MainloopSignal() const {
  DCHECK_GT(mainloop_lock_count_, 0);
  pa_threaded_mainloop_signal(pa_mainloop_, 0);
}

inline bool AudioMixerPulse::MainloopSafeLock() const {
  base::AutoLock lock(mixer_state_lock_);
  if ((mixer_state_ == SHUTTING_DOWN) || (!pa_mainloop_))
    return false;

  pa_threaded_mainloop_lock(pa_mainloop_);
  ++mainloop_lock_count_;
  return true;
}

inline bool AudioMixerPulse::MainloopLockIfReady() const {
  base::AutoLock lock(mixer_state_lock_);
  if (mixer_state_ != READY)
    return false;
  if (!pa_mainloop_)
    return false;
  pa_threaded_mainloop_lock(pa_mainloop_);
  ++mainloop_lock_count_;
  return true;
}

}  // namespace chromeos
<commit_msg>Fix flaky browser_tests incoming_queue_.empty() failure<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/chromeos/audio_mixer_pulse.h"

#include <pulse/pulseaudio.h>

#include "base/logging.h"
#include "base/message_loop.h"
#include "base/task.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/browser_thread.h"

namespace chromeos {

// Using asynchronous versions of the threaded PulseAudio API, as well
// as a worker thread so gets, sets, and the init sequence do not block the
// calling thread.  GetVolume() and IsMute() can still be called synchronously
// if needed, but take a bit longer (~2ms vs ~0.3ms).
//
// Set calls just return without waiting.  If you must guarantee the value has
// been set before continuing, immediately call the blocking Get version to
// synchronously get the value back.
//
// TODO(davej): Serialize volume/mute to preserve settings when restarting?

namespace {

const int kInvalidDeviceId = -1;

const double kMinVolumeDb = -90.0;
// Choosing 6.0dB here instead of 0dB to give user chance to amplify audio some
// in case sounds or their setup is too quiet for them.
const double kMaxVolumeDb = 6.0;

// Used for passing custom data to the PulseAudio callbacks.
struct CallbackWrapper {
  AudioMixerPulse* instance;
  bool done;
  void* userdata;
};

}  // namespace

// AudioInfo contains all the values we care about when getting info for a
// Sink (output device) used by GetAudioInfo().
struct AudioMixerPulse::AudioInfo {
  pa_cvolume cvolume;
  bool muted;
};

AudioMixerPulse::AudioMixerPulse()
    : device_id_(kInvalidDeviceId),
      last_channels_(0),
      mainloop_lock_count_(0),
      mixer_state_(UNINITIALIZED),
      pa_context_(NULL),
      pa_mainloop_(NULL) {
}

AudioMixerPulse::~AudioMixerPulse() {
  bool run_all_pending = false;
  {
    base::AutoLock lock(mixer_state_lock_);
    // DoInit() has not even been called yet, but is still in the thread message
    // queue.  Force it out of the queue and exit DoInit() right away.
    if ((!pa_mainloop_) && (mixer_state_ == INITIALIZING)) {
      mixer_state_ = UNINITIALIZED;
      run_all_pending = true;
    }
  }
  if (run_all_pending)
    thread_->message_loop()->RunAllPending();

  PulseAudioFree();
  if (thread_ != NULL) {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    // A ScopedAllowIO object is required to join the thread when calling Stop.
    // The worker thread should be idle at this time.
    // See http://crosbug.com/11110 for discussion.
    base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
    thread_->message_loop()->AssertIdle();

    thread_->Stop();
    thread_.reset();
  }
}

void AudioMixerPulse::Init(InitDoneCallback* callback) {
  DCHECK(callback);
  if (!InitThread()) {
    callback->Run(false);
    delete callback;
    return;
  }

  // Post the task of starting up, which can block for 200-500ms,
  // so best not to do it on the caller's thread.
  thread_->message_loop()->PostTask(FROM_HERE,
      NewRunnableMethod(this, &AudioMixerPulse::DoInit, callback));
}

bool AudioMixerPulse::InitSync() {
  if (!InitThread())
    return false;
  return PulseAudioInit();
}

double AudioMixerPulse::GetVolumeDb() const {
  if (!MainloopLockIfReady())
    return AudioMixer::kSilenceDb;
  AudioInfo data;
  GetAudioInfo(&data);
  MainloopUnlock();
  return pa_sw_volume_to_dB(data.cvolume.values[0]);
}

bool AudioMixerPulse::GetVolumeLimits(double* vol_min, double* vol_max) {
  if (vol_min)
    *vol_min = kMinVolumeDb;
  if (vol_max)
    *vol_max = kMaxVolumeDb;
  return true;
}

void AudioMixerPulse::SetVolumeDb(double vol_db) {
  if (!MainloopLockIfReady())
    return;

  // last_channels_ determines the number of channels on the main output device,
  // and is used later to set the volume on all channels at once.
  if (!last_channels_) {
    AudioInfo data;
    GetAudioInfo(&data);
    last_channels_ = data.cvolume.channels;
  }

  pa_operation* pa_op;
  pa_cvolume cvolume;
  pa_cvolume_set(&cvolume, last_channels_, pa_sw_volume_from_dB(vol_db));
  pa_op = pa_context_set_sink_volume_by_index(pa_context_, device_id_,
                                              &cvolume, NULL, NULL);
  pa_operation_unref(pa_op);
  MainloopUnlock();
  VLOG(1) << "Set volume to " << vol_db << " dB";
}

bool AudioMixerPulse::IsMute() const {
  if (!MainloopLockIfReady())
    return false;
  AudioInfo data;
  GetAudioInfo(&data);
  MainloopUnlock();
  return data.muted;
}

void AudioMixerPulse::SetMute(bool mute) {
  if (!MainloopLockIfReady())
    return;
  pa_operation* pa_op;
  pa_op = pa_context_set_sink_mute_by_index(pa_context_, device_id_,
                                            mute ? 1 : 0, NULL, NULL);
  pa_operation_unref(pa_op);
  MainloopUnlock();
  VLOG(1) << "Set mute to " << mute;
}

AudioMixer::State AudioMixerPulse::GetState() const {
  base::AutoLock lock(mixer_state_lock_);
  // If we think it's ready, verify it is actually so.
  if ((mixer_state_ == READY) &&
      (pa_context_get_state(pa_context_) != PA_CONTEXT_READY))
    mixer_state_ = IN_ERROR;
  return mixer_state_;
}

////////////////////////////////////////////////////////////////////////////////
// Private functions follow

void AudioMixerPulse::DoInit(InitDoneCallback* callback) {
  bool success = PulseAudioInit();
  callback->Run(success);
  delete callback;
}

bool AudioMixerPulse::InitThread() {
  base::AutoLock lock(mixer_state_lock_);

  if (mixer_state_ != UNINITIALIZED)
    return false;

  if (thread_ == NULL) {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    thread_.reset(new base::Thread("AudioMixerPulse"));
    if (!thread_->Start()) {
      thread_.reset();
      return false;
    }
  }
  mixer_state_ = INITIALIZING;
  return true;
}

// static
void AudioMixerPulse::ConnectToPulseCallbackThunk(
    pa_context* context, void* userdata) {
  CallbackWrapper* data =
      static_cast<CallbackWrapper*>(userdata);
  data->instance->OnConnectToPulseCallback(context, &data->done);
}

void AudioMixerPulse::OnConnectToPulseCallback(
    pa_context* context, bool* connect_done) {
  pa_context_state_t state = pa_context_get_state(context);
  if (state == PA_CONTEXT_READY ||
      state == PA_CONTEXT_FAILED ||
      state == PA_CONTEXT_TERMINATED) {
    // Connection process has reached a terminal state. Wake PulseAudioInit().
    *connect_done = true;
    MainloopSignal();
  }
}

bool AudioMixerPulse::PulseAudioInit() {
  pa_context_state_t state = PA_CONTEXT_FAILED;

  {
    base::AutoLock lock(mixer_state_lock_);
    if (mixer_state_ != INITIALIZING)
      return false;

    pa_mainloop_ = pa_threaded_mainloop_new();
    if (!pa_mainloop_) {
      LOG(ERROR) << "Can't create PulseAudio mainloop";
      mixer_state_ = UNINITIALIZED;
      return false;
    }

    if (pa_threaded_mainloop_start(pa_mainloop_) != 0) {
      LOG(ERROR) << "Can't start PulseAudio mainloop";
      pa_threaded_mainloop_free(pa_mainloop_);
      mixer_state_ = UNINITIALIZED;
      return false;
    }
  }

  while (true) {
    // Create connection to default server.
    if (!MainloopSafeLock())
      return false;

    while (true) {
      pa_mainloop_api* pa_mlapi = pa_threaded_mainloop_get_api(pa_mainloop_);
      if (!pa_mlapi) {
        LOG(ERROR) << "Can't get PulseAudio mainloop api";
        break;
      }
      // This one takes the most time if run at app startup.
      pa_context_ = pa_context_new(pa_mlapi, "ChromeAudio");
      if (!pa_context_) {
        LOG(ERROR) << "Can't create new PulseAudio context";
        break;
      }

      MainloopUnlock();
      if (!MainloopSafeLock())
        return false;

      CallbackWrapper data = {this, false, NULL};
      pa_context_set_state_callback(pa_context_,
                                    &ConnectToPulseCallbackThunk,
                                    &data);

      if (pa_context_connect(pa_context_, NULL,
                             PA_CONTEXT_NOAUTOSPAWN, NULL) != 0) {
        LOG(ERROR) << "Can't start connection to PulseAudio sound server";
      } else {
        // Wait until we have a completed connection or fail.
        do {
          MainloopWait();
        } while (!data.done);

        state = pa_context_get_state(pa_context_);

        if (state == PA_CONTEXT_FAILED) {
          LOG(ERROR) << "PulseAudio connection failed (daemon not running?)";
        } else if (state == PA_CONTEXT_TERMINATED) {
          LOG(ERROR) << "PulseAudio connection terminated early";
        } else if (state != PA_CONTEXT_READY) {
          LOG(ERROR) << "Unknown problem connecting to PulseAudio";
        }
      }

      pa_context_set_state_callback(pa_context_, NULL, NULL);
      break;
    }

    MainloopUnlock();

    if (state != PA_CONTEXT_READY)
      break;

    if (!MainloopSafeLock())
      return false;
    GetDefaultPlaybackDevice();
    MainloopUnlock();

    if (device_id_ == kInvalidDeviceId)
      break;

    {
      base::AutoLock lock(mixer_state_lock_);
      if (mixer_state_ == SHUTTING_DOWN)
        return false;
      mixer_state_ = READY;
    }

    return true;
  }

  // Failed startup sequence, clean up now.
  PulseAudioFree();
  return false;
}

void AudioMixerPulse::PulseAudioFree() {
  {
    base::AutoLock lock(mixer_state_lock_);
    if (!pa_mainloop_)
      mixer_state_ = UNINITIALIZED;
    if ((mixer_state_ == UNINITIALIZED) || (mixer_state_ == SHUTTING_DOWN))
      return;

    // If still initializing on another thread, this will cause it to exit.
    mixer_state_ = SHUTTING_DOWN;
  }

  DCHECK(pa_mainloop_);

  MainloopLock();
  if (pa_context_) {
    pa_context_disconnect(pa_context_);
    pa_context_unref(pa_context_);
    pa_context_ = NULL;
  }
  MainloopUnlock();

  pa_threaded_mainloop_stop(pa_mainloop_);
  pa_threaded_mainloop_free(pa_mainloop_);
  pa_mainloop_ = NULL;

  {
    base::AutoLock lock(mixer_state_lock_);
    mixer_state_ = UNINITIALIZED;
  }
}

void AudioMixerPulse::CompleteOperation(pa_operation* pa_op,
                                        bool* done) const {
  // After starting any operation, this helper checks if it started OK, then
  // waits for it to complete by iterating through the mainloop until the
  // operation is not running anymore.
  CHECK(pa_op);

  while (pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING) {
    // If operation still running, but we got what we needed, cancel it now.
    if (*done) {
      pa_operation_cancel(pa_op);
      break;
    }
    MainloopWait();
  }
  pa_operation_unref(pa_op);
}

// Must be called with mainloop lock held
void AudioMixerPulse::GetDefaultPlaybackDevice() {
  DCHECK_GT(mainloop_lock_count_, 0);
  DCHECK(pa_context_);
  DCHECK(pa_context_get_state(pa_context_) == PA_CONTEXT_READY);

  CallbackWrapper data = {this, false, NULL};

  pa_operation* pa_op = pa_context_get_sink_info_list(pa_context_,
                                        EnumerateDevicesCallback,
                                        &data);
  CompleteOperation(pa_op, &data.done);
  return;
}

void AudioMixerPulse::OnEnumerateDevices(const pa_sink_info* sink_info,
                                         int eol, bool* done) {
  if (device_id_ != kInvalidDeviceId)
    return;

  // TODO(davej): Should we handle cases of more than one output sink device?

  // eol is < 0 for error, > 0 for end of list, ==0 while listing.
  if (eol == 0) {
    device_id_ = sink_info->index;
  }
  *done = true;
  MainloopSignal();
}

// static
void AudioMixerPulse::EnumerateDevicesCallback(pa_context* unused,
                                               const pa_sink_info* sink_info,
                                               int eol,
                                               void* userdata) {
  CallbackWrapper* data =
      static_cast<CallbackWrapper*>(userdata);
  data->instance->OnEnumerateDevices(sink_info, eol, &data->done);
}

// Must be called with lock held
void AudioMixerPulse::GetAudioInfo(AudioInfo* info) const {
  DCHECK_GT(mainloop_lock_count_, 0);
  CallbackWrapper data = {const_cast<AudioMixerPulse*>(this), false, info};
  pa_operation* pa_op = pa_context_get_sink_info_by_index(pa_context_,
                                                          device_id_,
                                                          GetAudioInfoCallback,
                                                          &data);
  CompleteOperation(pa_op, &data.done);
}

// static
void AudioMixerPulse::GetAudioInfoCallback(pa_context* unused,
                                           const pa_sink_info* sink_info,
                                           int eol,
                                           void* userdata) {
  CallbackWrapper* data = static_cast<CallbackWrapper*>(userdata);
  AudioInfo* info = static_cast<AudioInfo*>(data->userdata);

  // Copy just the information we care about.
  if (eol == 0) {
    info->cvolume = sink_info->volume;
    info->muted = sink_info->mute ? true : false;
    data->done = true;
  }
  data->instance->MainloopSignal();
}

inline void AudioMixerPulse::MainloopLock() const {
  pa_threaded_mainloop_lock(pa_mainloop_);
  ++mainloop_lock_count_;
}

inline void AudioMixerPulse::MainloopUnlock() const {
  --mainloop_lock_count_;
  pa_threaded_mainloop_unlock(pa_mainloop_);
}

// Must be called with the lock held.
inline void AudioMixerPulse::MainloopWait() const {
  DCHECK_GT(mainloop_lock_count_, 0);
  pa_threaded_mainloop_wait(pa_mainloop_);
}

// Must be called with the lock held.
inline void AudioMixerPulse::MainloopSignal() const {
  DCHECK_GT(mainloop_lock_count_, 0);
  pa_threaded_mainloop_signal(pa_mainloop_, 0);
}

inline bool AudioMixerPulse::MainloopSafeLock() const {
  base::AutoLock lock(mixer_state_lock_);
  if ((mixer_state_ == SHUTTING_DOWN) || (!pa_mainloop_))
    return false;

  pa_threaded_mainloop_lock(pa_mainloop_);
  ++mainloop_lock_count_;
  return true;
}

inline bool AudioMixerPulse::MainloopLockIfReady() const {
  base::AutoLock lock(mixer_state_lock_);
  if (mixer_state_ != READY)
    return false;
  if (!pa_mainloop_)
    return false;
  pa_threaded_mainloop_lock(pa_mainloop_);
  ++mainloop_lock_count_;
  return true;
}

}  // namespace chromeos
<|endoftext|>


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

#include "chrome/browser/first_run/upgrade_util.h"

#include <windows.h>
#include <shellapi.h>

#include <algorithm>
#include <string>

#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/win/metro.h"
#include "base/win/registry.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "chrome/browser/first_run/upgrade_util_win.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/shell_util.h"
#include "chrome/installer/util/util_constants.h"
#include "google_update/google_update_idl.h"

namespace {

bool GetNewerChromeFile(FilePath* path) {
  if (!PathService::Get(base::DIR_EXE, path))
    return false;
  *path = path->Append(installer::kChromeNewExe);
  return true;
}

bool InvokeGoogleUpdateForRename() {
  base::win::ScopedComPtr<IProcessLauncher> ipl;
  if (!FAILED(ipl.CreateInstance(__uuidof(ProcessLauncherClass)))) {
    ULONG_PTR phandle = NULL;
    DWORD id = GetCurrentProcessId();
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    if (!FAILED(ipl->LaunchCmdElevated(dist->GetAppGuid().c_str(),
                                       google_update::kRegRenameCmdField,
                                       id,
                                       &phandle))) {
      HANDLE handle = HANDLE(phandle);
      WaitForSingleObject(handle, INFINITE);
      DWORD exit_code;
      ::GetExitCodeProcess(handle, &exit_code);
      ::CloseHandle(handle);
      if (exit_code == installer::RENAME_SUCCESSFUL)
        return true;
    }
  }
  return false;
}

FilePath GetMetroRelauncherPath(const FilePath& chrome_exe,
                                const std::string version_str) {
  FilePath path(chrome_exe.DirName());

  // The relauncher is ordinarily in the version directory.  When running in a
  // build tree however (where CHROME_VERSION is not set in the environment)
  // look for it in Chrome's directory.
  if (!version_str.empty())
    path = path.AppendASCII(version_str);

  return path.Append(installer::kDelegateExecuteExe);
}

}  // namespace

namespace upgrade_util {

bool RelaunchChromeHelper(const CommandLine& command_line, bool mode_switch) {
  scoped_ptr<base::Environment> env(base::Environment::Create());
  std::string version_str;

  // Get the version variable and remove it from the environment.
  if (env->GetVar(chrome::kChromeVersionEnvVar, &version_str))
    env->UnSetVar(chrome::kChromeVersionEnvVar);
  else
    version_str.clear();

  if (base::win::GetVersion() < base::win::VERSION_WIN8)
    return base::LaunchProcess(command_line, base::LaunchOptions(), NULL);

  // On Windows 8 we always use the delegate_execute for re-launching chrome.
  //
  // Pass this Chrome's Start Menu shortcut path to the relauncher so it can
  // re-activate chrome via ShellExecute.
  FilePath chrome_exe;
  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
    NOTREACHED();
    return false;
  }

  // We need to use ShellExecute to launch the relauncher, which will wait until
  // we exit. But ShellExecute does not support handle passing to the child
  // process so we create a uniquely named mutex that we aquire and never
  // release. So when we exit, Windows marks our mutex as abandoned and the
  // wait is satisfied.
  // The format of the named mutex is important. See DelegateExecuteOperation
  // for more details.
  string16 mutex_name =
      base::StringPrintf(L"chrome.relaunch.%d", ::GetCurrentProcessId());
  HANDLE mutex = ::CreateMutexW(NULL, TRUE, mutex_name.c_str());
  // The |mutex| handle needs to be leaked. See comment above.
  if (!mutex) {
    NOTREACHED();
    return false;
  }
  if (::GetLastError() == ERROR_ALREADY_EXISTS) {
    NOTREACHED() << "Relaunch mutex already exists";
    return false;
  }

  CommandLine relaunch_cmd(CommandLine::NO_PROGRAM);
  relaunch_cmd.AppendSwitchPath(switches::kRelaunchShortcut,
      ShellIntegration::GetStartMenuShortcut(chrome_exe));
  relaunch_cmd.AppendSwitchNative(switches::kWaitForMutex, mutex_name);

  if (mode_switch) {
    relaunch_cmd.AppendSwitch(base::win::IsMetroProcess() ?
        switches::kForceDesktop : switches::kForceImmersive);
  }

  string16 params(relaunch_cmd.GetCommandLineString());
  string16 path(GetMetroRelauncherPath(chrome_exe, version_str).value());

  SHELLEXECUTEINFO sei = { sizeof(sei) };
  sei.fMask = SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_NOCLOSEPROCESS;
  sei.nShow = SW_SHOWNORMAL;
  sei.lpFile = path.c_str();
  sei.lpParameters = params.c_str();

  if (!::ShellExecuteExW(&sei)) {
    NOTREACHED() << "ShellExecute failed with " << GetLastError();
    return false;
  }
  DWORD pid = ::GetProcessId(sei.hProcess);
  CloseHandle(sei.hProcess);
  if (!pid)
    return false;
  // The next call appears to be needed if we are relaunching from desktop into
  // metro mode. The observed effect if not done is that chrome starts in metro
  // mode but it is not given focus and it gets killed by windows after a few
  // seconds.
  ::AllowSetForegroundWindow(pid);
  return true;
}

bool RelaunchChromeBrowser(const CommandLine& command_line) {
  return RelaunchChromeHelper(command_line, false);
}

bool RelaunchChromeWithModeSwitch(const CommandLine& command_line) {
  return RelaunchChromeHelper(command_line, true);
}

bool IsUpdatePendingRestart() {
  FilePath new_chrome_exe;
  if (!GetNewerChromeFile(&new_chrome_exe))
    return false;
  return file_util::PathExists(new_chrome_exe);
}

bool SwapNewChromeExeIfPresent() {
  FilePath new_chrome_exe;
  if (!GetNewerChromeFile(&new_chrome_exe))
    return false;
  if (!file_util::PathExists(new_chrome_exe))
    return false;
  FilePath cur_chrome_exe;
  if (!PathService::Get(base::FILE_EXE, &cur_chrome_exe))
    return false;

  // Open up the registry key containing current version and rename information.
  bool user_install =
      InstallUtil::IsPerUserInstall(cur_chrome_exe.value().c_str());
  HKEY reg_root = user_install ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
  BrowserDistribution *dist = BrowserDistribution::GetDistribution();
  base::win::RegKey key;
  if (key.Open(reg_root, dist->GetVersionKey().c_str(),
               KEY_QUERY_VALUE) == ERROR_SUCCESS) {

    // Having just ascertained that we can swap, now check that we should: if
    // we are given an explicit --chrome-version flag, don't rename unless the
    // specified version matches the "pv" value. In practice, this is used to
    // defer Chrome Frame updates until the current version of the Chrome Frame
    // DLL component is loaded.
    const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
    if (cmd_line.HasSwitch(switches::kChromeVersion)) {
      std::string version_string =
          cmd_line.GetSwitchValueASCII(switches::kChromeVersion);
      Version cmd_version(version_string);

      std::wstring pv_value;
      if (key.ReadValue(google_update::kRegVersionField,
                        &pv_value) == ERROR_SUCCESS) {
        Version pv_version(WideToASCII(pv_value));
        if (cmd_version.IsValid() && pv_version.IsValid() &&
            !cmd_version.Equals(pv_version)) {
          return false;
        }
      }
    }

    // First try to rename exe by launching rename command ourselves.
    std::wstring rename_cmd;
    if (key.ReadValue(google_update::kRegRenameCmdField,
                      &rename_cmd) == ERROR_SUCCESS) {
      base::ProcessHandle handle;
      base::LaunchOptions options;
      options.wait = true;
      options.start_hidden = true;
      if (base::LaunchProcess(rename_cmd, options, &handle)) {
        DWORD exit_code;
        ::GetExitCodeProcess(handle, &exit_code);
        ::CloseHandle(handle);
        if (exit_code == installer::RENAME_SUCCESSFUL)
          return true;
      }
    }
  }

  // Rename didn't work so try to rename by calling Google Update
  return InvokeGoogleUpdateForRename();
}

bool DoUpgradeTasks(const CommandLine& command_line) {
  // The DelegateExecute verb handler finalizes pending in-use updates for
  // metro mode launches, as Chrome cannot be gracefully relaunched when
  // running in this mode.
  if (base::win::IsMetroProcess())
    return false;
  if (!SwapNewChromeExeIfPresent())
    return false;
  // At this point the chrome.exe has been swapped with the new one.
  if (!RelaunchChromeBrowser(command_line)) {
    // The re-launch fails. Feel free to panic now.
    NOTREACHED();
  }
  return true;
}

}  // namespace upgrade_util
<commit_msg>[Coverity] pass-by-val -> pass-by-ref<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/first_run/upgrade_util.h"

#include <windows.h>
#include <shellapi.h>

#include <algorithm>
#include <string>

#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/win/metro.h"
#include "base/win/registry.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "chrome/browser/first_run/upgrade_util_win.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/shell_util.h"
#include "chrome/installer/util/util_constants.h"
#include "google_update/google_update_idl.h"

namespace {

bool GetNewerChromeFile(FilePath* path) {
  if (!PathService::Get(base::DIR_EXE, path))
    return false;
  *path = path->Append(installer::kChromeNewExe);
  return true;
}

bool InvokeGoogleUpdateForRename() {
  base::win::ScopedComPtr<IProcessLauncher> ipl;
  if (!FAILED(ipl.CreateInstance(__uuidof(ProcessLauncherClass)))) {
    ULONG_PTR phandle = NULL;
    DWORD id = GetCurrentProcessId();
    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    if (!FAILED(ipl->LaunchCmdElevated(dist->GetAppGuid().c_str(),
                                       google_update::kRegRenameCmdField,
                                       id,
                                       &phandle))) {
      HANDLE handle = HANDLE(phandle);
      WaitForSingleObject(handle, INFINITE);
      DWORD exit_code;
      ::GetExitCodeProcess(handle, &exit_code);
      ::CloseHandle(handle);
      if (exit_code == installer::RENAME_SUCCESSFUL)
        return true;
    }
  }
  return false;
}

FilePath GetMetroRelauncherPath(const FilePath& chrome_exe,
                                const std::string& version_str) {
  FilePath path(chrome_exe.DirName());

  // The relauncher is ordinarily in the version directory.  When running in a
  // build tree however (where CHROME_VERSION is not set in the environment)
  // look for it in Chrome's directory.
  if (!version_str.empty())
    path = path.AppendASCII(version_str);

  return path.Append(installer::kDelegateExecuteExe);
}

}  // namespace

namespace upgrade_util {

bool RelaunchChromeHelper(const CommandLine& command_line, bool mode_switch) {
  scoped_ptr<base::Environment> env(base::Environment::Create());
  std::string version_str;

  // Get the version variable and remove it from the environment.
  if (env->GetVar(chrome::kChromeVersionEnvVar, &version_str))
    env->UnSetVar(chrome::kChromeVersionEnvVar);
  else
    version_str.clear();

  if (base::win::GetVersion() < base::win::VERSION_WIN8)
    return base::LaunchProcess(command_line, base::LaunchOptions(), NULL);

  // On Windows 8 we always use the delegate_execute for re-launching chrome.
  //
  // Pass this Chrome's Start Menu shortcut path to the relauncher so it can
  // re-activate chrome via ShellExecute.
  FilePath chrome_exe;
  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
    NOTREACHED();
    return false;
  }

  // We need to use ShellExecute to launch the relauncher, which will wait until
  // we exit. But ShellExecute does not support handle passing to the child
  // process so we create a uniquely named mutex that we aquire and never
  // release. So when we exit, Windows marks our mutex as abandoned and the
  // wait is satisfied.
  // The format of the named mutex is important. See DelegateExecuteOperation
  // for more details.
  string16 mutex_name =
      base::StringPrintf(L"chrome.relaunch.%d", ::GetCurrentProcessId());
  HANDLE mutex = ::CreateMutexW(NULL, TRUE, mutex_name.c_str());
  // The |mutex| handle needs to be leaked. See comment above.
  if (!mutex) {
    NOTREACHED();
    return false;
  }
  if (::GetLastError() == ERROR_ALREADY_EXISTS) {
    NOTREACHED() << "Relaunch mutex already exists";
    return false;
  }

  CommandLine relaunch_cmd(CommandLine::NO_PROGRAM);
  relaunch_cmd.AppendSwitchPath(switches::kRelaunchShortcut,
      ShellIntegration::GetStartMenuShortcut(chrome_exe));
  relaunch_cmd.AppendSwitchNative(switches::kWaitForMutex, mutex_name);

  if (mode_switch) {
    relaunch_cmd.AppendSwitch(base::win::IsMetroProcess() ?
        switches::kForceDesktop : switches::kForceImmersive);
  }

  string16 params(relaunch_cmd.GetCommandLineString());
  string16 path(GetMetroRelauncherPath(chrome_exe, version_str).value());

  SHELLEXECUTEINFO sei = { sizeof(sei) };
  sei.fMask = SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_NOCLOSEPROCESS;
  sei.nShow = SW_SHOWNORMAL;
  sei.lpFile = path.c_str();
  sei.lpParameters = params.c_str();

  if (!::ShellExecuteExW(&sei)) {
    NOTREACHED() << "ShellExecute failed with " << GetLastError();
    return false;
  }
  DWORD pid = ::GetProcessId(sei.hProcess);
  CloseHandle(sei.hProcess);
  if (!pid)
    return false;
  // The next call appears to be needed if we are relaunching from desktop into
  // metro mode. The observed effect if not done is that chrome starts in metro
  // mode but it is not given focus and it gets killed by windows after a few
  // seconds.
  ::AllowSetForegroundWindow(pid);
  return true;
}

bool RelaunchChromeBrowser(const CommandLine& command_line) {
  return RelaunchChromeHelper(command_line, false);
}

bool RelaunchChromeWithModeSwitch(const CommandLine& command_line) {
  return RelaunchChromeHelper(command_line, true);
}

bool IsUpdatePendingRestart() {
  FilePath new_chrome_exe;
  if (!GetNewerChromeFile(&new_chrome_exe))
    return false;
  return file_util::PathExists(new_chrome_exe);
}

bool SwapNewChromeExeIfPresent() {
  FilePath new_chrome_exe;
  if (!GetNewerChromeFile(&new_chrome_exe))
    return false;
  if (!file_util::PathExists(new_chrome_exe))
    return false;
  FilePath cur_chrome_exe;
  if (!PathService::Get(base::FILE_EXE, &cur_chrome_exe))
    return false;

  // Open up the registry key containing current version and rename information.
  bool user_install =
      InstallUtil::IsPerUserInstall(cur_chrome_exe.value().c_str());
  HKEY reg_root = user_install ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
  BrowserDistribution *dist = BrowserDistribution::GetDistribution();
  base::win::RegKey key;
  if (key.Open(reg_root, dist->GetVersionKey().c_str(),
               KEY_QUERY_VALUE) == ERROR_SUCCESS) {

    // Having just ascertained that we can swap, now check that we should: if
    // we are given an explicit --chrome-version flag, don't rename unless the
    // specified version matches the "pv" value. In practice, this is used to
    // defer Chrome Frame updates until the current version of the Chrome Frame
    // DLL component is loaded.
    const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
    if (cmd_line.HasSwitch(switches::kChromeVersion)) {
      std::string version_string =
          cmd_line.GetSwitchValueASCII(switches::kChromeVersion);
      Version cmd_version(version_string);

      std::wstring pv_value;
      if (key.ReadValue(google_update::kRegVersionField,
                        &pv_value) == ERROR_SUCCESS) {
        Version pv_version(WideToASCII(pv_value));
        if (cmd_version.IsValid() && pv_version.IsValid() &&
            !cmd_version.Equals(pv_version)) {
          return false;
        }
      }
    }

    // First try to rename exe by launching rename command ourselves.
    std::wstring rename_cmd;
    if (key.ReadValue(google_update::kRegRenameCmdField,
                      &rename_cmd) == ERROR_SUCCESS) {
      base::ProcessHandle handle;
      base::LaunchOptions options;
      options.wait = true;
      options.start_hidden = true;
      if (base::LaunchProcess(rename_cmd, options, &handle)) {
        DWORD exit_code;
        ::GetExitCodeProcess(handle, &exit_code);
        ::CloseHandle(handle);
        if (exit_code == installer::RENAME_SUCCESSFUL)
          return true;
      }
    }
  }

  // Rename didn't work so try to rename by calling Google Update
  return InvokeGoogleUpdateForRename();
}

bool DoUpgradeTasks(const CommandLine& command_line) {
  // The DelegateExecute verb handler finalizes pending in-use updates for
  // metro mode launches, as Chrome cannot be gracefully relaunched when
  // running in this mode.
  if (base::win::IsMetroProcess())
    return false;
  if (!SwapNewChromeExeIfPresent())
    return false;
  // At this point the chrome.exe has been swapped with the new one.
  if (!RelaunchChromeBrowser(command_line)) {
    // The re-launch fails. Feel free to panic now.
    NOTREACHED();
  }
  return true;
}

}  // namespace upgrade_util
<|endoftext|>


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

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

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "grit/generated_resources.h"
#include "grit/chromium_strings.h"

// static
void ImportLockDialogGtk::Show(GtkWindow* parent, ImporterHost* importer_host) {
  new ImportLockDialogGtk(parent, importer_host);
}

ImportLockDialogGtk::ImportLockDialogGtk(GtkWindow* parent,
    ImporterHost* importer_host) : importer_host_(importer_host) {
  // Build the dialog.
  dialog_ = gtk_dialog_new_with_buttons(
      l10n_util::GetStringUTF8(IDS_IMPORTER_LOCK_TITLE).c_str(),
      parent,
      (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
      GTK_STOCK_OK,
      GTK_RESPONSE_ACCEPT,
      GTK_STOCK_CANCEL,
      GTK_RESPONSE_REJECT,
      NULL);

  GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox;
  gtk_box_set_spacing(GTK_BOX(content_area), 18);
  GtkWidget* label = gtk_label_new(
      l10n_util::GetStringUTF8(IDS_IMPORTER_LOCK_TEXT).c_str());
  gtk_label_set_single_line_mode(GTK_LABEL(label), FALSE);
  gtk_box_pack_start(GTK_BOX(content_area), label, FALSE, FALSE, 0);

  g_signal_connect(dialog_, "response",
                   G_CALLBACK(HandleOnResponseDialog), this);
  gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE);
  gtk_widget_show_all(dialog_);
}

void ImportLockDialogGtk::OnDialogResponse(GtkWidget* widget, int response) {
  if (response == GTK_RESPONSE_ACCEPT) {
    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
        importer_host_.get(), &ImporterHost::OnLockViewEnd, true));
  } else {
    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
        importer_host_.get(), &ImporterHost::OnLockViewEnd, false));
  }
  gtk_widget_destroy(dialog_);
  delete this;
}
<commit_msg>Use custom strings for importer lock dialog.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "grit/generated_resources.h"
#include "grit/chromium_strings.h"

// static
void ImportLockDialogGtk::Show(GtkWindow* parent, ImporterHost* importer_host) {
  new ImportLockDialogGtk(parent, importer_host);
}

ImportLockDialogGtk::ImportLockDialogGtk(GtkWindow* parent,
    ImporterHost* importer_host) : importer_host_(importer_host) {
  // Build the dialog.
  dialog_ = gtk_dialog_new_with_buttons(
      l10n_util::GetStringUTF8(IDS_IMPORTER_LOCK_TITLE).c_str(),
      parent,
      (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
      l10n_util::GetStringUTF8(IDS_IMPORTER_LOCK_OK).c_str(),
      GTK_RESPONSE_ACCEPT,
      l10n_util::GetStringUTF8(IDS_IMPORTER_LOCK_CANCEL).c_str(),
      GTK_RESPONSE_REJECT,
      NULL);

  GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox;
  gtk_box_set_spacing(GTK_BOX(content_area), 18);
  GtkWidget* label = gtk_label_new(
      l10n_util::GetStringUTF8(IDS_IMPORTER_LOCK_TEXT).c_str());
  gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
  gtk_box_pack_start(GTK_BOX(content_area), label, FALSE, FALSE, 0);

  g_signal_connect(dialog_, "response",
                   G_CALLBACK(HandleOnResponseDialog), this);
  gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE);
  gtk_widget_show_all(dialog_);
}

void ImportLockDialogGtk::OnDialogResponse(GtkWidget* widget, int response) {
  if (response == GTK_RESPONSE_ACCEPT) {
    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
        importer_host_.get(), &ImporterHost::OnLockViewEnd, true));
  } else {
    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
        importer_host_.get(), &ImporterHost::OnLockViewEnd, false));
  }
  gtk_widget_destroy(dialog_);
  delete this;
}
<|endoftext|>


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

#include "chrome/common/extensions/extension_action.h"

#include "app/gfx/canvas.h"
#include "app/gfx/font.h"
#include "app/resource_bundle.h"
#include "base/gfx/rect.h"
#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "grit/app_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/effects/SkGradientShader.h"

namespace {

// Different platforms need slightly different constants to look good.
#if defined(OS_LINUX) && !defined(TOOLKIT_VIEWS)
const int kTextSize = 9;
const int kBottomMargin = 0;
const int kPadding = 2;
const int kTopTextPadding = 0;
#elif defined(OS_MACOSX)
const int kTextSize = 9;
const int kBottomMargin = 5;
const int kPadding = 2;
const int kTopTextPadding = 0;
#else
const int kTextSize = 8;
const int kBottomMargin = 5;
const int kPadding = 2;
// The padding between the top of the badge and the top of the text.
const int kTopTextPadding = 1;
#endif

const int kBadgeHeight = 11;
const int kMaxTextWidth = 23;
// The minimum width for center-aligning the badge.
const int kCenterAlignThreshold = 20;

#if defined(OS_MACOSX)
const char kPreferredTypeface[] = "Helvetica Bold";
#else
const char kPreferredTypeface[] = "Arial";
#endif

SkPaint* GetTextPaint() {
  static SkPaint* text_paint = NULL;
  if (!text_paint) {
    text_paint = new SkPaint;
    text_paint->setAntiAlias(true);

    text_paint->setTextAlign(SkPaint::kLeft_Align);
    text_paint->setTextSize(SkIntToScalar(kTextSize));

    SkTypeface* typeface = SkTypeface::CreateFromName(
        kPreferredTypeface, SkTypeface::kBold);
    // Skia doesn't do any font fallback---if the user is missing the font then
    // typeface will be NULL. If we don't do manual fallback then we'll crash.
    if (typeface) {
      text_paint->setFakeBoldText(true);
    } else {
      // Fall back to the system font. We don't bold it because we aren't sure
      // how it will look.
      // For the most part this code path will only be hit on Linux systems
      // that don't have Arial.
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont);
      typeface = SkTypeface::CreateFromName(
          WideToUTF8(base_font.FontName()).c_str(), SkTypeface::kNormal);
    }

    text_paint->setTypeface(typeface);
    // |text_paint| adds its own ref. Release the ref from CreateFontName.
    typeface->unref();
  }
  return text_paint;
}

}  // namespace

const int ExtensionAction::kDefaultTabId = -1;

void ExtensionAction::ClearAllValuesForTab(int tab_id) {
  title_.erase(tab_id);
  icon_.erase(tab_id);
  icon_index_.erase(tab_id);
  badge_text_.erase(tab_id);
  badge_text_color_.erase(tab_id);
  badge_background_color_.erase(tab_id);
  visible_.erase(tab_id);
  popup_url_.erase(tab_id);
}

void ExtensionAction::PaintBadge(gfx::Canvas* canvas,
                                 const gfx::Rect& bounds,
                                 int tab_id) {
  std::string text = GetBadgeText(tab_id);
  if (text.empty())
    return;

  SkColor text_color = GetBadgeTextColor(tab_id);
  SkColor background_color = GetBadgeBackgroundColor(tab_id);

  if (SkColorGetA(text_color) == 0x00)
    text_color = SK_ColorWHITE;

  if (SkColorGetA(background_color) == 0x00)
    background_color = SkColorSetARGB(255, 218, 0, 24);  // Default badge color.

  canvas->save();

  SkPaint* text_paint = GetTextPaint();
  text_paint->setColor(text_color);

  // Calculate text width. We clamp it to a max size.
  SkScalar text_width = text_paint->measureText(text.c_str(), text.size());
  text_width = SkIntToScalar(
      std::min(kMaxTextWidth, SkScalarFloor(text_width)));

  // Calculate badge size. It is clamped to a min width just because it looks
  // silly if it is too skinny.
  int badge_width = SkScalarFloor(text_width) + kPadding * 2;
  int icon_width = GetIcon(tab_id).width();
  // Force the pixel width of badge to be either odd (if the icon width is odd)
  // or even otherwise. If there is a mismatch you get http://crbug.com/26400.
  if (icon_width != 0 && (badge_width % 2 != GetIcon(tab_id).width() % 2))
    badge_width += 1;
  badge_width = std::max(kBadgeHeight, badge_width);

  // Paint the badge background color in the right location. It is usually
  // right-aligned, but it can also be center-aligned if it is large.
  SkRect rect;
  rect.fBottom = SkIntToScalar(bounds.bottom() - kBottomMargin);
  rect.fTop = rect.fBottom - SkIntToScalar(kBadgeHeight);
  if (badge_width >= kCenterAlignThreshold) {
    rect.fLeft = SkIntToScalar(
                     SkScalarFloor(SkIntToScalar(bounds.x()) +
                                   SkIntToScalar(bounds.width() / 2.0) -
                                   SkIntToScalar(badge_width / 2.0)));
    rect.fRight = rect.fLeft + SkIntToScalar(badge_width);
  } else {
    rect.fRight = SkIntToScalar(bounds.right());
    rect.fLeft = rect.fRight - badge_width;
  }

  SkPaint rect_paint;
  rect_paint.setStyle(SkPaint::kFill_Style);
  rect_paint.setAntiAlias(true);
  rect_paint.setColor(background_color);
  canvas->drawRoundRect(rect, SkIntToScalar(2), SkIntToScalar(2), rect_paint);

  // Overlay the gradient. It is stretchy, so we do this in three parts.
  ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
  SkBitmap* gradient_left = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_LEFT);
  SkBitmap* gradient_right = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_RIGHT);
  SkBitmap* gradient_center = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_CENTER);

  canvas->drawBitmap(*gradient_left, rect.fLeft, rect.fTop);
  canvas->TileImageInt(*gradient_center,
      SkScalarFloor(rect.fLeft) + gradient_left->width(),
      SkScalarFloor(rect.fTop),
      SkScalarFloor(rect.width()) - gradient_left->width() -
                    gradient_right->width(),
      SkScalarFloor(rect.height()));
  canvas->drawBitmap(*gradient_right,
      rect.fRight - SkIntToScalar(gradient_right->width()), rect.fTop);

  // Finally, draw the text centered within the badge. We set a clip in case the
  // text was too large.
  rect.fLeft += kPadding;
  rect.fRight -= kPadding;
  canvas->clipRect(rect);
  canvas->drawText(text.c_str(), text.size(),
                   rect.fLeft + (rect.width() - text_width) / 2,
                   rect.fTop + kTextSize + kTopTextPadding,
                   *text_paint);
  canvas->restore();
}
<commit_msg>Fix 32364: Badge text of Browser Action is displayed in bold font<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/common/extensions/extension_action.h"

#include "app/gfx/canvas.h"
#include "app/gfx/font.h"
#include "app/resource_bundle.h"
#include "base/gfx/rect.h"
#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "grit/app_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/effects/SkGradientShader.h"

namespace {

// Different platforms need slightly different constants to look good.
#if defined(OS_LINUX) && !defined(TOOLKIT_VIEWS)
const int kTextSize = 9;
const int kBottomMargin = 0;
const int kPadding = 2;
const int kTopTextPadding = 0;
#elif defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
const int kTextSize = 8;
const int kBottomMargin = 5;
const int kPadding = 2;
const int kTopTextPadding = 1;
#elif defined(OS_MACOSX)
const int kTextSize = 9;
const int kBottomMargin = 5;
const int kPadding = 2;
const int kTopTextPadding = 0;
#else
const int kTextSize = 7;
const int kBottomMargin = 5;
const int kPadding = 2;
// The padding between the top of the badge and the top of the text.
const int kTopTextPadding = 2;
#endif

const int kBadgeHeight = 11;
const int kMaxTextWidth = 23;
// The minimum width for center-aligning the badge.
const int kCenterAlignThreshold = 20;

#if defined(OS_MACOSX)
const char kPreferredTypeface[] = "Helvetica Bold";
#else
const char kPreferredTypeface[] = "Arial";
#endif

SkPaint* GetTextPaint() {
  static SkPaint* text_paint = NULL;
  if (!text_paint) {
    text_paint = new SkPaint;
    text_paint->setAntiAlias(true);

    text_paint->setTextAlign(SkPaint::kLeft_Align);
    text_paint->setTextSize(SkIntToScalar(kTextSize));

    SkTypeface* typeface = SkTypeface::CreateFromName(
        kPreferredTypeface, SkTypeface::kBold);
    // Skia doesn't do any font fallback---if the user is missing the font then
    // typeface will be NULL. If we don't do manual fallback then we'll crash.
    if (typeface) {
      text_paint->setFakeBoldText(true);
    } else {
      // Fall back to the system font. We don't bold it because we aren't sure
      // how it will look.
      // For the most part this code path will only be hit on Linux systems
      // that don't have Arial.
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont);
      typeface = SkTypeface::CreateFromName(
          WideToUTF8(base_font.FontName()).c_str(), SkTypeface::kNormal);
    }

    text_paint->setTypeface(typeface);
    // |text_paint| adds its own ref. Release the ref from CreateFontName.
    typeface->unref();
  }
  return text_paint;
}

}  // namespace

const int ExtensionAction::kDefaultTabId = -1;

void ExtensionAction::ClearAllValuesForTab(int tab_id) {
  title_.erase(tab_id);
  icon_.erase(tab_id);
  icon_index_.erase(tab_id);
  badge_text_.erase(tab_id);
  badge_text_color_.erase(tab_id);
  badge_background_color_.erase(tab_id);
  visible_.erase(tab_id);
  popup_url_.erase(tab_id);
}

void ExtensionAction::PaintBadge(gfx::Canvas* canvas,
                                 const gfx::Rect& bounds,
                                 int tab_id) {
  std::string text = GetBadgeText(tab_id);
  if (text.empty())
    return;

  SkColor text_color = GetBadgeTextColor(tab_id);
  SkColor background_color = GetBadgeBackgroundColor(tab_id);

  if (SkColorGetA(text_color) == 0x00)
    text_color = SK_ColorWHITE;

  if (SkColorGetA(background_color) == 0x00)
    background_color = SkColorSetARGB(255, 218, 0, 24);  // Default badge color.

  canvas->save();

  SkPaint* text_paint = GetTextPaint();
  text_paint->setColor(text_color);

  // Calculate text width. We clamp it to a max size.
  SkScalar text_width = text_paint->measureText(text.c_str(), text.size());
  text_width = SkIntToScalar(
      std::min(kMaxTextWidth, SkScalarFloor(text_width)));

  // Calculate badge size. It is clamped to a min width just because it looks
  // silly if it is too skinny.
  int badge_width = SkScalarFloor(text_width) + kPadding * 2;
  int icon_width = GetIcon(tab_id).width();
  // Force the pixel width of badge to be either odd (if the icon width is odd)
  // or even otherwise. If there is a mismatch you get http://crbug.com/26400.
  if (icon_width != 0 && (badge_width % 2 != GetIcon(tab_id).width() % 2))
    badge_width += 1;
  badge_width = std::max(kBadgeHeight, badge_width);

  // Paint the badge background color in the right location. It is usually
  // right-aligned, but it can also be center-aligned if it is large.
  SkRect rect;
  rect.fBottom = SkIntToScalar(bounds.bottom() - kBottomMargin);
  rect.fTop = rect.fBottom - SkIntToScalar(kBadgeHeight);
  if (badge_width >= kCenterAlignThreshold) {
    rect.fLeft = SkIntToScalar(
                     SkScalarFloor(SkIntToScalar(bounds.x()) +
                                   SkIntToScalar(bounds.width() / 2.0) -
                                   SkIntToScalar(badge_width / 2.0)));
    rect.fRight = rect.fLeft + SkIntToScalar(badge_width);
  } else {
    rect.fRight = SkIntToScalar(bounds.right());
    rect.fLeft = rect.fRight - badge_width;
  }

  SkPaint rect_paint;
  rect_paint.setStyle(SkPaint::kFill_Style);
  rect_paint.setAntiAlias(true);
  rect_paint.setColor(background_color);
  canvas->drawRoundRect(rect, SkIntToScalar(2), SkIntToScalar(2), rect_paint);

  // Overlay the gradient. It is stretchy, so we do this in three parts.
  ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
  SkBitmap* gradient_left = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_LEFT);
  SkBitmap* gradient_right = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_RIGHT);
  SkBitmap* gradient_center = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_CENTER);

  canvas->drawBitmap(*gradient_left, rect.fLeft, rect.fTop);
  canvas->TileImageInt(*gradient_center,
      SkScalarFloor(rect.fLeft) + gradient_left->width(),
      SkScalarFloor(rect.fTop),
      SkScalarFloor(rect.width()) - gradient_left->width() -
                    gradient_right->width(),
      SkScalarFloor(rect.height()));
  canvas->drawBitmap(*gradient_right,
      rect.fRight - SkIntToScalar(gradient_right->width()), rect.fTop);

  // Finally, draw the text centered within the badge. We set a clip in case the
  // text was too large.
  rect.fLeft += kPadding;
  rect.fRight -= kPadding;
  canvas->clipRect(rect);
  canvas->drawText(text.c_str(), text.size(),
                   rect.fLeft + (rect.width() - text_width) / 2,
                   rect.fTop + kTextSize + kTopTextPadding,
                   *text_paint);
  canvas->restore();
}
<|endoftext|>


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

#include "chrome/common/profile_management_switches.h"

#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "chrome/common/chrome_switches.h"

namespace {

const char kNewProfileManagementFieldTrialName[] = "NewProfileManagement";

bool CheckProfileManagementFlag(std::string command_switch, bool active_state) {
  std::string trial_type =
      base::FieldTrialList::FindFullName(kNewProfileManagementFieldTrialName);
  if (!trial_type.empty()) {
    if (trial_type == "Enabled")
      return active_state;
    if (trial_type == "Disabled")
      return !active_state;
  }
  return CommandLine::ForCurrentProcess()->HasSwitch(command_switch);
}

}  // namespace

namespace switches {

bool IsEnableWebBasedSignin() {
  return CheckProfileManagementFlag(switches::kEnableWebBasedSignin, false);
}

bool IsGoogleProfileInfo() {
  return CheckProfileManagementFlag(switches::kGoogleProfileInfo, true);
}

bool IsNewProfileManagement() {
  return CheckProfileManagementFlag(switches::kNewProfileManagement, true);
}

}  // namespace switches
<commit_msg>Use --new-profile-management to set all related flags.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/profile_management_switches.h"

#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "chrome/common/chrome_switches.h"

namespace {

const char kNewProfileManagementFieldTrialName[] = "NewProfileManagement";

bool CheckProfileManagementFlag(std::string command_switch, bool active_state) {
  // Individiual flag settings take precedence.
  if (CommandLine::ForCurrentProcess()->HasSwitch(command_switch)) {
    return true;
  }

  // --new-profile-management flag always affects all switches.
  if (CommandLine::ForCurrentProcess()->HasSwitch(
        switches::kNewProfileManagement)) {
    return active_state;
  }

  // NewProfileManagement experiment acts like above flag.
  std::string trial_type =
      base::FieldTrialList::FindFullName(kNewProfileManagementFieldTrialName);
  if (!trial_type.empty()) {
    if (trial_type == "Enabled")
      return active_state;
    if (trial_type == "Disabled")
      return !active_state;
  }

  return false;
}

}  // namespace

namespace switches {

bool IsEnableWebBasedSignin() {
  return CheckProfileManagementFlag(switches::kEnableWebBasedSignin, false);
}

bool IsGoogleProfileInfo() {
  return CheckProfileManagementFlag(switches::kGoogleProfileInfo, true);
}

bool IsNewProfileManagement() {
  return CheckProfileManagementFlag(switches::kNewProfileManagement, true);
}

}  // namespace switches
<|endoftext|>