Back to index

lightning-sunbird  0.9+nobinonly
nsSystemPrefService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 /* ***** BEGIN LICENSE BLOCK *****
00005  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  *
00008  * The contents of this file are subject to the Mozilla Public
00009  * License Version 1.1 (the "License"); you may not use this file
00010  * except in compliance with the License. You may obtain a copy of
00011  * the License at http://www.mozilla.org/MPL/
00012  *
00013  * Software distributed under the License is distributed on an "AS
00014  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
00015  * implied. See the License for the specific language governing
00016  * rights and limitations under the License.
00017  *
00018  * The Original Code is mozilla.org code.
00019  *
00020  * The Initial Developer of the Original Code is Sun Microsystems, Inc.
00021  * Portions created by Sun Microsystems are Copyright (C) 2003 Sun
00022  * Microsystems, Inc. All Rights Reserved.
00023  *
00024  * Original Author: Bolian Yin (bolian.yin@sun.com)
00025  *
00026  * Contributor(s):
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either the GNU General Public License Version 2 or later (the "GPL"), or
00030  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the NPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the NPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include <glib.h>
00043 #include <glib-object.h>
00044 
00045 #include "plstr.h"
00046 #include "nsCOMPtr.h"
00047 #include "nsIPref.h"
00048 #include "nsIServiceManager.h"
00049 #include "nsIObserver.h"
00050 #include "nsWeakReference.h"
00051 
00052 #include "nsString.h"
00053 #include "nsSystemPrefLog.h"
00054 #include "nsSystemPrefService.h"
00055 
00056 /*************************************************************************
00057  * The strange thing here is that we load the gconf library manually and 
00058  * search the function pointers we need. If that process fails, no gconf
00059  * support is available in mozilla. The aim is to make mozilla independent
00060  * on gconf, in both compile time and run time.
00061  ************************************************************************/
00062 
00063 //gconf types
00064 extern "C" {
00065 
00066     typedef enum {
00067         GCONF_VALUE_INVALID,
00068         GCONF_VALUE_STRING,
00069         GCONF_VALUE_INT,
00070         GCONF_VALUE_FLOAT,
00071         GCONF_VALUE_BOOL,
00072         GCONF_VALUE_SCHEMA,
00073 
00074         GCONF_VALUE_LIST,
00075         GCONF_VALUE_PAIR
00076 
00077     }GConfValueType;
00078 
00079     typedef struct {
00080         GConfValueType type;
00081     }GConfValue;
00082 
00083     typedef void * (*GConfClientGetDefaultType) (void);
00084     typedef PRBool (*GConfClientGetBoolType) (void *client, const gchar *key,
00085                                               GError **err);
00086     typedef gchar* (*GConfClientGetStringType) (void *client, const gchar *key,
00087                                                 GError **err);
00088     typedef PRInt32 (*GConfClientGetIntType) (void *client, const gchar *key,
00089                                               GError **err);
00090     typedef  void (*GConfClientNotifyFuncType) (void* client, guint cnxn_id,
00091                                                 void *entry, 
00092                                                 gpointer user_data);
00093     typedef guint (*GConfClientNotifyAddType) (void* client,
00094                                                const gchar* namespace_section,
00095                                                GConfClientNotifyFuncType func,
00096                                                gpointer user_data,
00097                                                GFreeFunc destroy_notify,
00098                                                GError** err);
00099     typedef void (*GConfClientNotifyRemoveType) (void *client,
00100                                                  guint cnxn);
00101     typedef void (*GConfClientAddDirType) (void *client,
00102                                            const gchar *dir,
00103                                            guint8 preload,
00104                                            GError **err);
00105     typedef void (*GConfClientRemoveDirType) (void *client,
00106                                               const gchar *dir,
00107                                               GError **err);
00108 
00109     typedef const char* (*GConfEntryGetKeyType) (const void *entry);
00110     typedef GConfValue* (*GConfEntryGetValueType) (const void *entry);
00111 
00112     typedef const char* (*GConfValueGetStringType) (const GConfValue *value);
00113     typedef PRInt32 (*GConfValueGetIntType) (const GConfValue *value);
00114     typedef PRBool (*GConfValueGetBoolType) (const GConfValue *value);
00115 
00116     
00117     static void gconf_key_listener (void* client, guint cnxn_id,
00118                                     void *entry, gpointer user_data);
00119 }
00120 
00121 struct GConfCallbackData
00122 {
00123     GConfProxy *proxy;
00124     void * userData;
00125     PRUint32 atom;
00126     PRUint32 notifyId;
00127 };
00129 // GConPrxoy is a thin wrapper for easy use of gconf funcs. It loads the
00130 // gconf library and initializes the func pointers for later use.
00132 class GConfProxy
00133 {
00134 public:
00135     GConfProxy(nsSystemPrefService* aSysPrefService);
00136     ~GConfProxy();
00137     PRBool Init();
00138 
00139     nsresult GetBoolPref(const char *aMozKey, PRBool *retval);
00140     nsresult GetCharPref(const char *aMozKey, char **retval);
00141     nsresult GetIntPref(const char *aMozKey, PRInt32 *retval);
00142 
00143     nsresult NotifyAdd (PRUint32 aAtom, void *aUserData);
00144     nsresult NotifyRemove (PRUint32 aAtom, const void *aUserData);
00145 
00146     nsresult GetAtomForMozKey(const char *aMozKey, PRUint32 *aAtom) {
00147         return GetAtom(aMozKey, 0, aAtom); 
00148     }
00149     const char *GetMozKey(PRUint32 aAtom) {
00150         return GetKey(aAtom, 0); 
00151     }
00152 
00153     void OnNotify(void *aClient, void * aEntry, PRUint32 aNotifyId,
00154                   GConfCallbackData *aData);
00155 
00156 private:
00157     void *mGConfClient;
00158     PRLibrary *mGConfLib;
00159     PRBool mInitialized;
00160     nsSystemPrefService *mSysPrefService;
00161 
00162     //listeners
00163     nsAutoVoidArray *mObservers;
00164 
00165     void InitFuncPtrs();
00166     //gconf public func ptrs
00167 
00168     //gconf client funcs
00169     GConfClientGetDefaultType GConfClientGetDefault;
00170     GConfClientGetBoolType GConfClientGetBool;
00171     GConfClientGetStringType GConfClientGetString;
00172     GConfClientGetIntType GConfClientGetInt;
00173     GConfClientNotifyAddType GConfClientNotifyAdd;
00174     GConfClientNotifyRemoveType GConfClientNotifyRemove;
00175     GConfClientAddDirType GConfClientAddDir;
00176     GConfClientRemoveDirType GConfClientRemoveDir;
00177 
00178     //gconf entry funcs
00179     GConfEntryGetValueType GConfEntryGetValue;
00180     GConfEntryGetKeyType GConfEntryGetKey;
00181 
00182     //gconf value funcs
00183     GConfValueGetBoolType GConfValueGetBool;
00184     GConfValueGetStringType GConfValueGetString;
00185     GConfValueGetIntType GConfValueGetInt;
00186 
00187     //pref name translating stuff
00188     nsresult GetAtom(const char *aKey, PRUint8 aNameType, PRUint32 *aAtom);
00189     nsresult GetAtomForGConfKey(const char *aGConfKey, PRUint32 *aAtom) \
00190     {return GetAtom(aGConfKey, 1, aAtom);}
00191     const char *GetKey(PRUint32 aAtom, PRUint8 aNameType);
00192     const char *GetGConfKey(PRUint32 aAtom) \
00193     {return GetKey(aAtom, 1); }
00194     inline const char *MozKey2GConfKey(const char *aMozKey);
00195 
00196     //const strings
00197     static const char sPrefGConfKey[];
00198     static const char sDefaultLibName1[];
00199     static const char sDefaultLibName2[];
00200 };
00201 
00202 struct SysPrefCallbackData {
00203     nsISupports *observer;
00204     PRBool bIsWeakRef;
00205     PRUint32 prefAtom;
00206 };
00207 
00208 PRBool PR_CALLBACK
00209 sysPrefDeleteObserver(void *aElement, void *aData) {
00210     SysPrefCallbackData *pElement =
00211         NS_STATIC_CAST(SysPrefCallbackData *, aElement);
00212     NS_RELEASE(pElement->observer);
00213     nsMemory::Free(pElement);
00214     return PR_TRUE;
00215 }
00216 
00217 NS_IMPL_ISUPPORTS2(nsSystemPrefService, nsIPrefBranch, nsIPrefBranch2)
00218 
00219 /* public */
00220 nsSystemPrefService::nsSystemPrefService()
00221     :mInitialized(PR_FALSE),
00222      mGConf(nsnull),
00223      mObservers(nsnull)
00224 {
00225 }
00226 
00227 nsSystemPrefService::~nsSystemPrefService()
00228 {
00229     mInitialized = PR_FALSE;
00230 
00231     if (mGConf)
00232         delete mGConf;
00233     if (mObservers) {
00234         (void)mObservers->EnumerateForwards(sysPrefDeleteObserver, nsnull);
00235         delete mObservers;
00236     }
00237 }
00238 
00239 nsresult
00240 nsSystemPrefService::Init()
00241 {
00242     if (!gSysPrefLog) {
00243         gSysPrefLog = PR_NewLogModule("Syspref");
00244         if (!gSysPrefLog) return NS_ERROR_OUT_OF_MEMORY;
00245     }
00246 
00247     SYSPREF_LOG(("Init SystemPref Service\n"));
00248     if (mInitialized)
00249         return NS_ERROR_FAILURE;
00250 
00251     if (!mGConf) {
00252         mGConf = new GConfProxy(this);
00253         if (!mGConf->Init()) {
00254             delete mGConf;
00255             mGConf = nsnull;
00256             return NS_ERROR_FAILURE;
00257         }
00258     }
00259 
00260     mInitialized = PR_TRUE;
00261     return NS_OK;
00262 }
00263 
00264 /* readonly attribute string root; */
00265 NS_IMETHODIMP nsSystemPrefService::GetRoot(char * *aRoot)
00266 {
00267     return NS_ERROR_NOT_IMPLEMENTED;
00268 }
00269 
00270 /* long getPrefType (in string aPrefName); */
00271 NS_IMETHODIMP nsSystemPrefService::GetPrefType(const char *aPrefName, PRInt32 *_retval)
00272 {
00273     return NS_ERROR_NOT_IMPLEMENTED;
00274 }
00275 
00276 /* boolean getBoolPref (in string aPrefName); */
00277 NS_IMETHODIMP nsSystemPrefService::GetBoolPref(const char *aPrefName, PRBool *_retval)
00278 {
00279     return mInitialized ?
00280         mGConf->GetBoolPref(aPrefName, _retval) : NS_ERROR_FAILURE;
00281 }
00282 
00283 /* void setBoolPref (in string aPrefName, in long aValue); */
00284 NS_IMETHODIMP nsSystemPrefService::SetBoolPref(const char *aPrefName, PRInt32 aValue)
00285 {
00286     return NS_ERROR_NOT_IMPLEMENTED;
00287 }
00288 
00289 /* string getCharPref (in string aPrefName); */
00290 NS_IMETHODIMP nsSystemPrefService::GetCharPref(const char *aPrefName, char **_retval)
00291 {
00292     return mInitialized ?
00293         mGConf->GetCharPref(aPrefName, _retval) : NS_ERROR_FAILURE;
00294 }
00295 
00296 /* void setCharPref (in string aPrefName, in string aValue); */
00297 NS_IMETHODIMP nsSystemPrefService::SetCharPref(const char *aPrefName, const char *aValue)
00298 {
00299     return NS_ERROR_NOT_IMPLEMENTED;
00300 }
00301 
00302 /* long getIntPref (in string aPrefName); */
00303 NS_IMETHODIMP nsSystemPrefService::GetIntPref(const char *aPrefName, PRInt32 *_retval)
00304 {
00305     return mInitialized ?
00306         mGConf->GetIntPref(aPrefName, _retval) : NS_ERROR_FAILURE;
00307 }
00308 
00309 /* void setIntPref (in string aPrefName, in long aValue); */
00310 NS_IMETHODIMP nsSystemPrefService::SetIntPref(const char *aPrefName, PRInt32 aValue)
00311 {
00312     return NS_ERROR_NOT_IMPLEMENTED;
00313 }
00314 
00315 /* void getComplexValue (in string aPrefName, in nsIIDRef aType, [iid_is (aType), retval] out nsQIResult aValue); */
00316 NS_IMETHODIMP nsSystemPrefService::GetComplexValue(const char *aPrefName, const nsIID & aType, void * *aValue)
00317 {
00318     return NS_ERROR_NOT_IMPLEMENTED;
00319 }
00320 
00321 /* void setComplexValue (in string aPrefName, in nsIIDRef aType, in nsISupports aValue); */
00322 NS_IMETHODIMP nsSystemPrefService::SetComplexValue(const char *aPrefName, const nsIID & aType, nsISupports *aValue)
00323 {
00324     return NS_ERROR_NOT_IMPLEMENTED;
00325 }
00326 
00327 /* void clearUserPref (in string aPrefName); */
00328 NS_IMETHODIMP nsSystemPrefService::ClearUserPref(const char *aPrefName)
00329 {
00330     return NS_ERROR_NOT_IMPLEMENTED;
00331 }
00332 
00333 /* void lockPref (in string aPrefName); */
00334 NS_IMETHODIMP nsSystemPrefService::LockPref(const char *aPrefName)
00335 {
00336     return NS_ERROR_NOT_IMPLEMENTED;
00337 }
00338 
00339 /* boolean prefHasUserValue (in string aPrefName); */
00340 NS_IMETHODIMP nsSystemPrefService::PrefHasUserValue(const char *aPrefName, PRBool *_retval)
00341 {
00342     return NS_ERROR_NOT_IMPLEMENTED;
00343 }
00344 
00345 /* boolean prefIsLocked (in string aPrefName); */
00346 NS_IMETHODIMP nsSystemPrefService::PrefIsLocked(const char *aPrefName, PRBool *_retval)
00347 {
00348     return NS_ERROR_NOT_IMPLEMENTED;
00349 }
00350 
00351 /* void unlockPref (in string aPrefName); */
00352 NS_IMETHODIMP nsSystemPrefService::UnlockPref(const char *aPrefName)
00353 {
00354     return NS_ERROR_NOT_IMPLEMENTED;
00355 }
00356 
00357 /* void deleteBranch (in string aStartingAt); */
00358 NS_IMETHODIMP nsSystemPrefService::DeleteBranch(const char *aStartingAt)
00359 {
00360     return NS_ERROR_NOT_IMPLEMENTED;
00361 }
00362 
00363 /* void getChildList (in string aStartingAt, out unsigned long aCount, [array, size_is (aCount), retval] out string aChildArray); */
00364 NS_IMETHODIMP nsSystemPrefService::GetChildList(const char *aStartingAt, PRUint32 *aCount, char ***aChildArray)
00365 {
00366     return NS_ERROR_NOT_IMPLEMENTED;
00367 }
00368 
00369 /* void resetBranch (in string aStartingAt); */
00370 NS_IMETHODIMP nsSystemPrefService::ResetBranch(const char *aStartingAt)
00371 {
00372     return NS_ERROR_NOT_IMPLEMENTED;
00373 }
00374 
00375 /* void addObserver (in string aDomain, in nsIObserver aObserver, in boolean aHoldWeak); */
00376 NS_IMETHODIMP nsSystemPrefService::AddObserver(const char *aDomain, nsIObserver *aObserver, PRBool aHoldWeak)
00377 {
00378     nsresult rv;
00379 
00380     NS_ENSURE_ARG_POINTER(aDomain);
00381     NS_ENSURE_ARG_POINTER(aObserver);
00382 
00383     NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
00384 
00385     PRUint32 prefAtom;
00386     // make sure the pref name is supported
00387     rv = mGConf->GetAtomForMozKey(aDomain, &prefAtom);
00388     NS_ENSURE_SUCCESS(rv, rv);
00389 
00390     if (!mObservers) {
00391         mObservers = new nsAutoVoidArray();
00392         if (mObservers == nsnull)
00393             return NS_ERROR_OUT_OF_MEMORY;
00394     }
00395 
00396     SysPrefCallbackData *pCallbackData = (SysPrefCallbackData *)
00397         nsMemory::Alloc(sizeof(SysPrefCallbackData));
00398     if (pCallbackData == nsnull)
00399         return NS_ERROR_OUT_OF_MEMORY;
00400 
00401     pCallbackData->bIsWeakRef = aHoldWeak;
00402     pCallbackData->prefAtom = prefAtom;
00403     // hold a weak reference to the observer if so requested
00404     nsCOMPtr<nsISupports> observerRef;
00405     if (aHoldWeak) {
00406         nsCOMPtr<nsISupportsWeakReference> weakRefFactory = 
00407             do_QueryInterface(aObserver);
00408         if (!weakRefFactory) {
00409             // the caller didn't give us a object that supports weak reference.
00410             // ... tell them
00411             nsMemory::Free(pCallbackData);
00412             return NS_ERROR_INVALID_ARG;
00413         }
00414         nsCOMPtr<nsIWeakReference> tmp = do_GetWeakReference(weakRefFactory);
00415         observerRef = tmp;
00416     } else {
00417         observerRef = aObserver;
00418     }
00419 
00420     rv = mGConf->NotifyAdd(prefAtom, pCallbackData);
00421     if (NS_FAILED(rv)) {
00422         nsMemory::Free(pCallbackData);
00423         return rv;
00424     }
00425 
00426     pCallbackData->observer = observerRef;
00427     NS_ADDREF(pCallbackData->observer);
00428 
00429     mObservers->AppendElement(pCallbackData);
00430     return NS_OK;
00431 }
00432 
00433 /* void removeObserver (in string aDomain, in nsIObserver aObserver); */
00434 NS_IMETHODIMP nsSystemPrefService::RemoveObserver(const char *aDomain, nsIObserver *aObserver)
00435 {
00436     nsresult rv;
00437 
00438     NS_ENSURE_ARG_POINTER(aDomain);
00439     NS_ENSURE_ARG_POINTER(aObserver);
00440     NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
00441 
00442     if (!mObservers)
00443         return NS_OK;
00444     
00445     PRUint32 prefAtom;
00446     // make sure the pref name is supported
00447     rv = mGConf->GetAtomForMozKey(aDomain, &prefAtom);
00448     NS_ENSURE_SUCCESS(rv, rv);
00449 
00450     // need to find the index of observer, so we can remove it
00451     PRIntn count = mObservers->Count();
00452     if (count <= 0)
00453         return NS_OK;
00454 
00455     PRIntn i;
00456     SysPrefCallbackData *pCallbackData;
00457     for (i = 0; i < count; ++i) {
00458         pCallbackData = (SysPrefCallbackData *)mObservers->ElementAt(i);
00459         if (pCallbackData) {
00460             nsCOMPtr<nsISupports> observerRef;
00461             if (pCallbackData->bIsWeakRef) {
00462                 nsCOMPtr<nsISupportsWeakReference> weakRefFactory =
00463                     do_QueryInterface(aObserver);
00464                 if (weakRefFactory) {
00465                     nsCOMPtr<nsIWeakReference> tmp =
00466                         do_GetWeakReference(aObserver);
00467                     observerRef = tmp;
00468                 }
00469             }
00470             if (!observerRef)
00471                 observerRef = aObserver;
00472 
00473             if (pCallbackData->observer == observerRef &&
00474                 pCallbackData->prefAtom == prefAtom) {
00475                 rv = mGConf->NotifyRemove(prefAtom, pCallbackData);
00476                 if (NS_SUCCEEDED(rv)) {
00477                     mObservers->RemoveElementAt(i);
00478                     NS_RELEASE(pCallbackData->observer);
00479                     nsMemory::Free(pCallbackData);
00480                 }
00481                 return rv;
00482             }
00483         }
00484     }
00485     return NS_OK;
00486 }
00487 
00488 void
00489 nsSystemPrefService::OnPrefChange(PRUint32 aPrefAtom, void *aData)
00490 {
00491     if (!mInitialized)
00492         return;
00493 
00494     SysPrefCallbackData *pData = (SysPrefCallbackData *)aData;
00495     if (pData->prefAtom != aPrefAtom)
00496         return;
00497 
00498     nsCOMPtr<nsIObserver> observer;
00499     if (pData->bIsWeakRef) {
00500         nsCOMPtr<nsIWeakReference> weakRef =
00501             do_QueryInterface(pData->observer);
00502         if(weakRef)
00503             observer = do_QueryReferent(weakRef);
00504         if (!observer) {
00505             // this weak referenced observer went away, remove it from the list
00506             nsresult rv = mGConf->NotifyRemove(aPrefAtom, pData);
00507             if (NS_SUCCEEDED(rv)) {
00508                 mObservers->RemoveElement(pData);
00509                 NS_RELEASE(pData->observer);
00510                 nsMemory::Free(pData);
00511             }
00512             return;
00513         }
00514     }
00515     else
00516         observer = do_QueryInterface(pData->observer);
00517 
00518     if (observer)
00519         observer->Observe(NS_STATIC_CAST(nsIPrefBranch *, this),
00520                           NS_SYSTEMPREF_PREFCHANGE_TOPIC_ID,
00521                           NS_ConvertUTF8toUCS2(mGConf->GetMozKey(aPrefAtom)).
00522                           get());
00523 }
00524 
00525 /*************************************************************
00526  *  GConfProxy
00527  *
00528  ************************************************************/
00529 
00530 struct GConfFuncListType {
00531     const char *FuncName;
00532     PRFuncPtr  FuncPtr;
00533 };
00534 
00535 struct PrefNamePair {
00536     const char *mozPrefName;
00537     const char *gconfPrefName;
00538 };
00539 
00540 const char
00541 GConfProxy::sPrefGConfKey[] = "accessibility.unix.gconf2.shared-library";
00542 const char GConfProxy::sDefaultLibName1[] = "libgconf-2.so.4";
00543 const char GConfProxy::sDefaultLibName2[] = "libgconf-2.so";
00544 
00545 #define GCONF_FUNCS_POINTER_BEGIN \
00546     static GConfFuncListType sGConfFuncList[] = {
00547 #define GCONF_FUNCS_POINTER_ADD(func_name) \
00548     {func_name, nsnull},
00549 #define GCONF_FUNCS_POINTER_END \
00550     {nsnull, nsnull}, };
00551 
00552 GCONF_FUNCS_POINTER_BEGIN
00553     GCONF_FUNCS_POINTER_ADD("gconf_client_get_default")        // 0
00554     GCONF_FUNCS_POINTER_ADD("gconf_client_get_bool")       // 1
00555     GCONF_FUNCS_POINTER_ADD("gconf_client_get_string")     //2
00556     GCONF_FUNCS_POINTER_ADD("gconf_client_get_int")       //3
00557     GCONF_FUNCS_POINTER_ADD("gconf_client_notify_add")   //4
00558     GCONF_FUNCS_POINTER_ADD("gconf_client_notify_remove")   //5
00559     GCONF_FUNCS_POINTER_ADD("gconf_client_add_dir")   //6
00560     GCONF_FUNCS_POINTER_ADD("gconf_client_remove_dir")   //7
00561     GCONF_FUNCS_POINTER_ADD("gconf_entry_get_value")       //8
00562     GCONF_FUNCS_POINTER_ADD("gconf_entry_get_key")       //9
00563     GCONF_FUNCS_POINTER_ADD("gconf_value_get_bool")      //10
00564     GCONF_FUNCS_POINTER_ADD("gconf_value_get_string")     //11
00565     GCONF_FUNCS_POINTER_ADD("gconf_value_get_int")       //12
00566 GCONF_FUNCS_POINTER_END
00567 
00569 // the list is the mapping table, between mozilla prefs and gconf prefs
00570 // It is expected to include all the pref pairs that are related in mozilla
00571 // and gconf. 
00572 //
00573 // Note: the prefs listed here are not neccessarily be read from gconf, they
00574 //       are the prefs that could be read from gconf. Mozilla has another
00575 //       list (see sSysPrefList in nsSystemPref.cpp) that decide which prefs
00576 //       are really read.
00578 
00579 static const PrefNamePair sPrefNameMapping[] = {
00580 #include "gconf_pref_list.inc"
00581     {nsnull, nsnull},
00582 };
00583 
00584 PRBool PR_CALLBACK
00585 gconfDeleteObserver(void *aElement, void *aData) {
00586     nsMemory::Free(aElement);
00587     return PR_TRUE;
00588 }
00589 
00590 GConfProxy::GConfProxy(nsSystemPrefService *aSysPrefService):
00591     mGConfClient(nsnull),
00592     mGConfLib(nsnull),
00593     mInitialized(PR_FALSE),
00594     mSysPrefService(aSysPrefService),
00595     mObservers(nsnull)
00596 {
00597 }
00598 
00599 GConfProxy::~GConfProxy()
00600 {
00601     if (mGConfClient)
00602         g_object_unref(G_OBJECT(mGConfClient));
00603 
00604     if (mObservers) {
00605         (void)mObservers->EnumerateForwards(gconfDeleteObserver, nsnull);
00606         delete mObservers;
00607     }
00608 }
00609 
00610 PRBool
00611 GConfProxy::Init()
00612 {
00613     SYSPREF_LOG(("GConfProxy:: Init GConfProxy\n"));
00614     if (!mSysPrefService)
00615         return PR_FALSE;
00616     if (mInitialized)
00617         return PR_TRUE;
00618 
00619     nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID);
00620     if (!pref)
00621         return PR_FALSE;
00622 
00623     nsXPIDLCString gconfLibName;
00624     nsresult rv;
00625 
00626     //check if gconf-2 library is given in prefs
00627     rv = pref->GetCharPref(sPrefGConfKey, getter_Copies(gconfLibName));
00628     if (NS_SUCCEEDED(rv)) {
00629         //use the library name in the preference
00630         SYSPREF_LOG(("GConf library in prefs is %s\n", gconfLibName.get()));
00631         mGConfLib = PR_LoadLibrary(gconfLibName.get());
00632     }
00633     else {
00634         SYSPREF_LOG(("GConf library not specified in prefs, try the default: "
00635                      "%s and %s\n", sDefaultLibName1, sDefaultLibName2));
00636         mGConfLib = PR_LoadLibrary(sDefaultLibName1);
00637         if (!mGConfLib)
00638             mGConfLib = PR_LoadLibrary(sDefaultLibName2);
00639     }
00640 
00641     if (!mGConfLib) {
00642         SYSPREF_LOG(("Fail to load GConf library\n"));
00643         return PR_FALSE;
00644     }
00645 
00646     //check every func we need in the gconf library
00647     GConfFuncListType *funcList;
00648     PRFuncPtr func;
00649     for (funcList = sGConfFuncList; funcList->FuncName; ++funcList) {
00650         func = PR_FindFunctionSymbol(mGConfLib, funcList->FuncName);
00651         if (!func) {
00652             SYSPREF_LOG(("Check GConf Func Error: %s", funcList->FuncName));
00653             goto init_failed_unload;
00654         }
00655         funcList->FuncPtr = func;
00656     }
00657 
00658     InitFuncPtrs();
00659 
00660     mGConfClient = GConfClientGetDefault();
00661 
00662     // Don't unload past this point, since GConf's initialization of ORBit
00663     // causes atexit handlers to be registered.
00664 
00665     if (!mGConfClient) {
00666         SYSPREF_LOG(("Fail to Get default gconf client\n"));
00667         goto init_failed;
00668     }
00669     mInitialized = PR_TRUE;
00670     return PR_TRUE;
00671 
00672  init_failed_unload:
00673     PR_UnloadLibrary(mGConfLib);
00674  init_failed:
00675     mGConfLib = nsnull;
00676     return PR_FALSE;
00677 }
00678 
00679 nsresult
00680 GConfProxy::GetBoolPref(const char *aMozKey, PRBool *retval)
00681 {
00682     NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
00683     *retval = GConfClientGetBool(mGConfClient, MozKey2GConfKey(aMozKey), NULL);
00684     return NS_OK;
00685 }
00686 
00687 nsresult
00688 GConfProxy::GetCharPref(const char *aMozKey, char **retval)
00689 {
00690     NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
00691 
00692     gchar *str = GConfClientGetString(mGConfClient,
00693                                       MozKey2GConfKey(aMozKey), NULL);
00694     if (str) {
00695         *retval = PL_strdup(str);
00696         g_free(str);
00697     }
00698     return NS_OK;
00699 }
00700 
00701 nsresult
00702 GConfProxy::GetIntPref(const char *aMozKey, PRInt32 *retval)
00703 {
00704     NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
00705     if (strcmp (aMozKey, "network.proxy.type") == 0) {
00706        gchar *str;
00707 
00708        str = GConfClientGetString(mGConfClient,
00709                                   MozKey2GConfKey (aMozKey), NULL);
00710 
00711        if (str) {
00712               if (strcmp (str, "manual") == 0)
00713                      *retval = 1;
00714               else if (strcmp (str, "auto") == 0)
00715                      *retval = 2;
00716               else
00717                      *retval = 0;
00718 
00719               g_free (str);
00720        } else
00721               *retval = 0;
00722     } else {
00723        *retval = GConfClientGetInt(mGConfClient, 
00724                                    MozKey2GConfKey(aMozKey), NULL);
00725     }
00726 
00727     return NS_OK;
00728 }
00729 
00730 nsresult
00731 GConfProxy::NotifyAdd (PRUint32 aAtom, void *aUserData)
00732 {
00733     NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
00734 
00735     const char *gconfKey = GetGConfKey(aAtom);
00736     if (!gconfKey)
00737         return NS_ERROR_FAILURE;
00738 
00739     if (!mObservers) {
00740         mObservers = new nsAutoVoidArray();
00741         if (mObservers == nsnull)
00742             return NS_ERROR_OUT_OF_MEMORY;
00743     }
00744  
00745     GConfCallbackData *pData = (GConfCallbackData *)
00746         nsMemory::Alloc(sizeof(GConfCallbackData));
00747     NS_ENSURE_TRUE(pData, NS_ERROR_OUT_OF_MEMORY);
00748 
00749     pData->proxy = this;
00750     pData->userData = aUserData;
00751     pData->atom = aAtom;
00752     mObservers->AppendElement(pData);
00753 
00754     GConfClientAddDir(mGConfClient, gconfKey,
00755                       0, // GCONF_CLIENT_PRELOAD_NONE,  don't preload anything 
00756                       NULL);
00757 
00758     pData->notifyId = GConfClientNotifyAdd(mGConfClient, gconfKey,
00759                                            gconf_key_listener, pData,
00760                                            NULL, NULL);
00761     return NS_OK;
00762 }
00763 
00764 nsresult
00765 GConfProxy::NotifyRemove (PRUint32 aAtom, const void *aUserData)
00766 {
00767     NS_ENSURE_TRUE(mInitialized, NS_ERROR_FAILURE);
00768 
00769     PRIntn count = mObservers->Count();
00770     if (count <= 0)
00771         return NS_OK;
00772 
00773     PRIntn i;
00774     GConfCallbackData *pData;
00775     for (i = 0; i < count; ++i) {
00776         pData = (GConfCallbackData *)mObservers->ElementAt(i);
00777         if (pData && pData->atom == aAtom && pData->userData == aUserData) {
00778             GConfClientNotifyRemove(mGConfClient, pData->notifyId);
00779             GConfClientRemoveDir(mGConfClient,
00780                                  GetGConfKey(pData->atom), NULL);
00781             mObservers->RemoveElementAt(i);
00782             nsMemory::Free(pData);
00783             break;
00784         }
00785     }
00786     return NS_OK;
00787 }
00788 
00789 void
00790 GConfProxy::InitFuncPtrs()
00791 {
00792     //gconf client funcs
00793     GConfClientGetDefault =
00794         (GConfClientGetDefaultType) sGConfFuncList[0].FuncPtr;
00795     GConfClientGetBool =
00796         (GConfClientGetBoolType) sGConfFuncList[1].FuncPtr;
00797     GConfClientGetString =
00798         (GConfClientGetStringType) sGConfFuncList[2].FuncPtr;
00799     GConfClientGetInt =
00800         (GConfClientGetIntType) sGConfFuncList[3].FuncPtr;
00801     GConfClientNotifyAdd =
00802         (GConfClientNotifyAddType) sGConfFuncList[4].FuncPtr;
00803     GConfClientNotifyRemove =
00804         (GConfClientNotifyRemoveType) sGConfFuncList[5].FuncPtr;
00805     GConfClientAddDir =
00806         (GConfClientAddDirType) sGConfFuncList[6].FuncPtr;
00807     GConfClientRemoveDir =
00808         (GConfClientRemoveDirType) sGConfFuncList[7].FuncPtr;
00809 
00810     //gconf entry funcs
00811     GConfEntryGetValue = (GConfEntryGetValueType) sGConfFuncList[8].FuncPtr;
00812     GConfEntryGetKey = (GConfEntryGetKeyType) sGConfFuncList[9].FuncPtr;
00813 
00814     //gconf value funcs
00815     GConfValueGetBool = (GConfValueGetBoolType) sGConfFuncList[10].FuncPtr;
00816     GConfValueGetString = (GConfValueGetStringType) sGConfFuncList[11].FuncPtr;
00817     GConfValueGetInt = (GConfValueGetIntType) sGConfFuncList[12].FuncPtr;
00818 }
00819 
00820 void
00821 GConfProxy::OnNotify(void *aClient, void * aEntry, PRUint32 aNotifyId,
00822                      GConfCallbackData *aData)
00823 {
00824     if (!mInitialized || !aEntry || (mGConfClient != aClient) || !aData)
00825         return;
00826 
00827     if (GConfEntryGetValue(aEntry) == NULL)
00828         return;
00829 
00830     PRUint32 prefAtom;
00831     nsresult rv = GetAtomForGConfKey(GConfEntryGetKey(aEntry), &prefAtom);
00832     if (NS_FAILED(rv))
00833         return;
00834 
00835     mSysPrefService->OnPrefChange(prefAtom, aData->userData);
00836 }
00837 
00838 nsresult
00839 GConfProxy::GetAtom(const char *aKey, PRUint8 aNameType, PRUint32 *aAtom)
00840 {
00841     if (!aKey)
00842         return NS_ERROR_FAILURE;
00843     PRUint32 prefSize = sizeof(sPrefNameMapping) / sizeof(sPrefNameMapping[0]);
00844     for (PRUint32 index = 0; index < prefSize; ++index) {
00845         if (!strcmp((aNameType == 0) ? sPrefNameMapping[index].mozPrefName :
00846                     sPrefNameMapping[index].gconfPrefName, aKey)) {
00847             *aAtom = index;
00848             return NS_OK;
00849         }
00850     }
00851     return NS_ERROR_FAILURE;
00852 }
00853 
00854 const char *
00855 GConfProxy::GetKey(PRUint32 aAtom, PRUint8 aNameType)
00856 {
00857     PRUint32 mapSize = sizeof(sPrefNameMapping) / sizeof(sPrefNameMapping[0]);
00858     if (aAtom >= 0 && aAtom < mapSize)
00859         return (aNameType == 0) ? sPrefNameMapping[aAtom].mozPrefName :
00860             sPrefNameMapping[aAtom].gconfPrefName;
00861     return NULL;
00862 }
00863 
00864 inline const char *
00865 GConfProxy::MozKey2GConfKey(const char *aMozKey)
00866 {
00867     PRUint32 atom;
00868     nsresult rv = GetAtomForMozKey(aMozKey, &atom);
00869     if (NS_SUCCEEDED(rv))
00870         return GetGConfKey(atom);
00871     return NULL;
00872 }
00873 
00874 /* static */
00875 void gconf_key_listener (void* client, guint cnxn_id,
00876                          void *entry, gpointer user_data)
00877 {
00878     SYSPREF_LOG(("...SYSPREF_LOG...key listener get called \n"));
00879     if (!user_data)
00880         return;
00881     GConfCallbackData *pData = NS_REINTERPRET_CAST(GConfCallbackData *,
00882                                                    user_data);
00883     pData->proxy->OnNotify(client, entry, cnxn_id, pData);
00884 }