Back to index

lightning-sunbird  0.9+nobinonly
nsToolkitBase.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla code.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corp..
00018  * Portions created by the Initial Developer are Copyright (C) 2003
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *    Simon Fraser <sfraser@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 
00039 #include <ctype.h>
00040 #include <stdlib.h>
00041 #include <stdio.h>
00042 
00043 #include <mach/mach_port.h>
00044 #include <mach/mach_interface.h>
00045 #include <mach/mach_init.h>
00046 
00047 #include <IOKit/pwr_mgt/IOPMLib.h>
00048 #include <IOKit/IOMessage.h>
00049 
00050 #include <CoreFoundation/CoreFoundation.h>
00051 #include <Carbon/Carbon.h>
00052 
00053 #include "nsToolkitBase.h"
00054 #include "nsWidgetAtoms.h"
00055 
00056 #include "nsIEventQueue.h"
00057 #include "nsIEventQueueService.h"
00058 #include "nsIObserverService.h"
00059 #include "nsIServiceManager.h"
00060 #include "nsIPref.h"
00061 
00062 
00063 static io_connect_t gRootPort = nsnull;
00064 
00065 static const char kQuartzRenderingPref[] = "browser.quartz.enable";
00066 static const char kAllFontSizesPref[] = "browser.quartz.enable.all_font_sizes";
00067 
00068 //
00069 // Static thread local storage index of the Toolkit 
00070 // object associated with a given thread...
00071 //
00072 static PRUintn gToolkitTLSIndex = 0;
00073 
00074 
00075 nsToolkitBase::nsToolkitBase()
00076 : mInited(false)
00077 , mSleepWakeNotificationRLS(nsnull)
00078 {
00079 
00080 }
00081 
00082 nsToolkitBase::~nsToolkitBase()
00083 {
00084   RemoveSleepWakeNotifcations();
00085   // Remove the TLS reference to the toolkit...
00086   PR_SetThreadPrivate(gToolkitTLSIndex, nsnull);
00087 }
00088 
00089 NS_IMPL_THREADSAFE_ISUPPORTS1(nsToolkitBase, nsIToolkit);
00090 
00091 NS_IMETHODIMP
00092 nsToolkitBase::Init(PRThread * aThread)
00093 {
00094   nsresult rv = InitEventQueue(aThread);
00095   if (NS_FAILED(rv)) return rv;
00096 
00097   nsWidgetAtoms::RegisterAtoms();
00098 
00099   mInited = true;
00100 
00101   RegisterForSleepWakeNotifcations();
00102   SetupQuartzRendering();
00103 
00104   nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID);
00105   if (prefs) {
00106     prefs->RegisterCallback(kQuartzRenderingPref, QuartzChangedCallback, nsnull);  
00107     prefs->RegisterCallback(kAllFontSizesPref, QuartzChangedCallback, nsnull);
00108   }
00109   return NS_OK;
00110 }
00111 
00112 
00113 //
00114 // QuartzChangedCallback
00115 //
00116 // The pref changed, reset the app to use quartz rendering as dictated by the pref
00117 //
00118 int nsToolkitBase::QuartzChangedCallback(const char* pref, void* data)
00119 {
00120   SetupQuartzRendering();
00121   return NS_OK;
00122 }
00123 
00124 //
00125 // SetupQuartzRendering
00126 //
00127 // Use apple's technote for 10.1.5 to turn on quartz rendering with CG metrics. This
00128 // slows us down about 12% when turned on.
00129 //
00130 void nsToolkitBase::SetupQuartzRendering()
00131 {
00132   // from Apple's technote at http://developer.apple.com/qa/qa2001/qa1193.html
00133   enum {
00134     kQDDontChangeFlags = 0xFFFFFFFF,         // don't change anything
00135     kQDUseDefaultTextRendering = 0,          // bit 0
00136     kQDUseTrueTypeScalerGlyphs = (1 << 0),   // bit 1
00137     kQDUseCGTextRendering = (1 << 1),        // bit 2
00138     kQDUseCGTextMetrics = (1 << 2)
00139   };
00140 
00141   const int kFlagsWeUse = kQDUseCGTextRendering | kQDUseCGTextMetrics;
00142 
00143   // turn on quartz rendering if we find the symbol in the app framework. Just turn
00144   // on the bits that we need, don't turn off what someone else might have wanted. If
00145   // the pref isn't found, assume we want it on. That way, we have to explicitly put
00146   // in a pref to disable it, rather than force everyone who wants it to carry around
00147   // an extra pref.
00148   nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID);
00149   if (!prefs)
00150     return;
00151 
00152   PRBool enableQuartz = PR_TRUE;
00153   nsresult rv = prefs->GetBoolPref(kQuartzRenderingPref, &enableQuartz);
00154   UInt32 oldFlags = QDSwapTextFlags(kQDDontChangeFlags);
00155   if (NS_FAILED(rv) || enableQuartz) {
00156     QDSwapTextFlags(oldFlags | kFlagsWeUse);
00157     
00158     // the system defaults to not anti-aliasing small fonts, but some people
00159     // think it looks better that way. If the pref is set, turn them on
00160     PRBool antiAliasAllFontSizes = PR_FALSE;
00161     rv = prefs->GetBoolPref(kAllFontSizesPref, &antiAliasAllFontSizes);
00162     if (NS_SUCCEEDED(rv) && antiAliasAllFontSizes)
00163       SetOutlinePreferred(true);
00164   }
00165   else 
00166     QDSwapTextFlags(oldFlags & !kFlagsWeUse);
00167 }
00168 
00169 
00170 // see
00171 // http://developer.apple.com/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/PowerMgmt/chapter_10_section_3.html
00172 
00173 static void ToolkitSleepWakeCallback(void *refCon, io_service_t service, natural_t messageType, void * messageArgument)
00174 {
00175   switch (messageType)
00176   {
00177     case kIOMessageSystemWillSleep:
00178       // System is going to sleep now.
00179       nsToolkitBase::PostSleepWakeNotification("sleep_notification");
00180       ::IOAllowPowerChange(gRootPort, (long)messageArgument);
00181       break;
00182 
00183     case kIOMessageCanSystemSleep:
00184       // In this case, the computer has been idle for several minutes
00185       // and will sleep soon so you must either allow or cancel
00186       // this notification. Important: if you donŐt respond, there will
00187       // be a 30-second timeout before the computer sleeps.
00188       // In Mozilla's case, we always allow sleep.
00189       ::IOAllowPowerChange(gRootPort,(long)messageArgument);
00190       break;
00191 
00192     case kIOMessageSystemHasPoweredOn:
00193       // Handle wakeup.
00194       nsToolkitBase::PostSleepWakeNotification("wake_notification");
00195       break;
00196   }
00197 }
00198 
00199 void
00200 nsToolkitBase::PostSleepWakeNotification(const char* aNotification)
00201 {
00202   nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
00203   if (observerService)
00204   {
00205     observerService->NotifyObservers(nsnull, aNotification, nsnull);
00206   }
00207 }
00208 
00209 nsresult
00210 nsToolkitBase::RegisterForSleepWakeNotifcations()
00211 {
00212   IONotificationPortRef   notifyPortRef;
00213 
00214   NS_ASSERTION(!mSleepWakeNotificationRLS, "Already registered for sleep/wake");
00215 
00216   gRootPort = ::IORegisterForSystemPower(0, &notifyPortRef, ToolkitSleepWakeCallback, &mPowerNotifier);
00217   if (gRootPort == NULL)
00218   {
00219     NS_ASSERTION(0, "IORegisterForSystemPower failed");
00220     return NS_ERROR_FAILURE;
00221   }
00222 
00223   mSleepWakeNotificationRLS = ::IONotificationPortGetRunLoopSource(notifyPortRef);
00224   ::CFRunLoopAddSource(::CFRunLoopGetCurrent(),
00225                         mSleepWakeNotificationRLS,
00226                         kCFRunLoopDefaultMode);
00227 
00228   return NS_OK;
00229 }
00230 
00231 
00232 void
00233 nsToolkitBase::RemoveSleepWakeNotifcations()
00234 {
00235   if (mSleepWakeNotificationRLS)
00236   {
00237     ::IODeregisterForSystemPower(&mPowerNotifier);
00238     ::CFRunLoopRemoveSource(::CFRunLoopGetCurrent(),
00239                           mSleepWakeNotificationRLS,
00240                           kCFRunLoopDefaultMode);
00241 
00242     mSleepWakeNotificationRLS = nsnull;
00243   }
00244 }
00245 
00246 
00247 #pragma mark -
00248 
00249 
00250 //-------------------------------------------------------------------------
00251 //
00252 // Return the nsIToolkit for the current thread.  If a toolkit does not
00253 // yet exist, then one will be created...
00254 //
00255 //-------------------------------------------------------------------------
00256 NS_METHOD NS_GetCurrentToolkit(nsIToolkit* *aResult)
00257 {
00258   NS_ENSURE_ARG_POINTER(aResult);
00259   *aResult = nsnull;
00260 
00261   // Create the TLS index the first time through...
00262   if (gToolkitTLSIndex == 0)
00263   {
00264     PRStatus status = PR_NewThreadPrivateIndex(&gToolkitTLSIndex, NULL);
00265     if (PR_FAILURE == status)
00266       return NS_ERROR_FAILURE;
00267   }
00268 
00269   //
00270   // Create a new toolkit for this thread...
00271   //
00272   nsToolkitBase* toolkit = (nsToolkitBase*)PR_GetThreadPrivate(gToolkitTLSIndex);
00273   if (!toolkit)
00274   {
00275     toolkit = NS_CreateToolkitInstance();
00276     if (!toolkit)
00277       return NS_ERROR_OUT_OF_MEMORY;
00278 
00279     NS_ADDREF(toolkit);
00280     toolkit->Init(PR_GetCurrentThread());
00281     //
00282     // The reference stored in the TLS is weak.  It is removed in the
00283     // nsToolkit destructor...
00284     //
00285     PR_SetThreadPrivate(gToolkitTLSIndex, (void*)toolkit);
00286   }
00287   else
00288   {
00289     NS_ADDREF(toolkit);
00290   }
00291   *aResult = toolkit;
00292   return NS_OK;
00293 }