Back to index

lightning-sunbird  0.9+nobinonly
nsAppShell.cpp
Go to the documentation of this file.
00001 /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
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 #include "prmon.h"
00039 #include "plhash.h"
00040 #include "nsCOMPtr.h"
00041 #include "nsAppShell.h"
00042 #include "nsIAppShell.h"
00043 #include "nsIServiceManager.h"
00044 #include "nsIEventQueueService.h"
00045 
00046 #include <stdlib.h>
00047 
00048 #include "nsIWidget.h"
00049 #include "nsIPref.h"
00050 #include "nsCRT.h"
00051 
00052 #include <Pt.h>
00053 #include <errno.h>
00054 
00055 /* Global Definitions */
00056 PRBool nsAppShell::gExitMainLoop = PR_FALSE;
00057 
00058 static PLHashTable *sQueueHashTable = nsnull;
00059 static PLHashTable *sCountHashTable = nsnull;
00060 
00061 // Set our static member
00062 PRBool nsAppShell::mPtInited = PR_FALSE;
00063 
00064 //-------------------------------------------------------------------------
00065 //
00066 // XPCOM CIDs
00067 //
00068 //-------------------------------------------------------------------------
00069 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00070 
00071 //-------------------------------------------------------------------------
00072 //
00073 // nsAppShell constructor
00074 //
00075 //-------------------------------------------------------------------------
00076 nsAppShell::nsAppShell()  
00077 {
00078   mEventQueue  = nsnull;
00079   mFD          = -1;
00080 }
00081 
00082 //-------------------------------------------------------------------------
00083 //
00084 // nsAppShell destructor
00085 //
00086 //-------------------------------------------------------------------------
00087 nsAppShell::~nsAppShell()
00088 {
00089   if (mFD != -1)
00090   {
00091     int err=PtAppRemoveFd(NULL,mFD);
00092 
00093     if (err==-1)
00094     {
00095          NS_WARNING("nsAppShell::~EventQueueTokenQueue Run Error calling PtAppRemoveFd");
00096 #ifdef DEBUG
00097          printf("nsAppShell::~EventQueueTokenQueue Run Error calling PtAppRemoveFd mFD=<%d> errno=<%d>\n", mFD, errno);
00098 #endif
00099     }  
00100     mFD = -1;
00101   }
00102 }
00103 
00104 
00105 //-------------------------------------------------------------------------
00106 //
00107 // nsISupports implementation macro
00108 //
00109 //-------------------------------------------------------------------------
00110 NS_IMPL_ISUPPORTS1(nsAppShell, nsIAppShell)
00111 
00112 //-------------------------------------------------------------------------
00113 //
00114 // Enter a message handler loop
00115 //
00116 //-------------------------------------------------------------------------
00117 
00118 static int event_processor_callback(int fd, void *data, unsigned mode)
00119 {
00120        nsIEventQueue *eventQueue = (nsIEventQueue*)data;
00121        PtHold();
00122        if (eventQueue)
00123           eventQueue->ProcessPendingEvents();
00124        PtRelease();
00125   return Pt_CONTINUE;
00126 }
00127 
00128 
00129 //-------------------------------------------------------------------------
00130 //
00131 // Create the application shell
00132 //
00133 //-------------------------------------------------------------------------
00134 
00135 NS_IMETHODIMP nsAppShell::Create(int *bac, char **bav)
00136 {
00137        /*
00138        This used to be done in the init function of nsToolkit. It was moved here because the phoenix
00139        browser may ( when -ProfileManager is used ) create/ListenToEventQueue of an nsAppShell before
00140        the toolkit is initialized and ListenToEventQueue relies on the Pt being already initialized
00141        */
00142        if( !mPtInited )
00143        {
00144               PtInit( NULL );
00145               PtChannelCreate(); // Force use of pulses
00146               mPtInited = PR_TRUE;
00147               PgSetDrawBufferSize( 0xffff );
00148        }
00149 
00150   return NS_OK;
00151 }
00152 
00153 //-------------------------------------------------------------------------
00154 //
00155 // Spinup - do any preparation necessary for running a message loop
00156 //
00157 //-------------------------------------------------------------------------
00158 NS_METHOD nsAppShell::Spinup()
00159 {
00160   nsresult   rv = NS_OK;
00161 
00162   // Get the event queue service
00163   nsCOMPtr<nsIEventQueueService> eventQService = do_GetService(kEventQueueServiceCID, &rv);
00164 
00165   if (NS_FAILED(rv)) {
00166     NS_ASSERTION("Could not obtain event queue service", PR_FALSE);
00167     return rv;
00168   }
00169 
00170   //Get the event queue for the thread.
00171        rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue));
00172 
00173   // If we got an event queue, use it.
00174   if (mEventQueue)
00175     goto done;
00176 
00177   // otherwise create a new event queue for the thread
00178   rv = eventQService->CreateThreadEventQueue();
00179   if (NS_FAILED(rv)) {
00180     NS_ASSERTION("Could not create the thread event queue", PR_FALSE);
00181     return rv;
00182   }
00183 
00184   // Ask again nicely for the event queue now that we have created one.
00185        rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue));
00186 
00187   // XXX shouldn't this be automatic?
00188  done:
00189   ListenToEventQueue(mEventQueue, PR_TRUE);
00190 
00191   return rv;
00192 }
00193 
00194 //-------------------------------------------------------------------------
00195 //
00196 // Spindown - do any cleanup necessary for finishing a message loop
00197 //
00198 //-------------------------------------------------------------------------
00199 NS_METHOD nsAppShell::Spindown()
00200 {
00201   if (mEventQueue) {
00202     ListenToEventQueue(mEventQueue, PR_FALSE);
00203     mEventQueue->ProcessPendingEvents();
00204     mEventQueue = nsnull;
00205   }
00206 
00207   return NS_OK;
00208 }
00209 
00210 /* This routine replaces the standard PtMainLoop() for Photon */
00211 /* We had to replace it to provide a mechanism (ExitMainLoop) to exit */
00212 /* the loop. */
00213 
00214 void MyMainLoop( void ) 
00215 {
00216        nsAppShell::gExitMainLoop = PR_FALSE;
00217        while (! nsAppShell::gExitMainLoop)
00218        {
00219               PtProcessEvent();
00220        }
00221 
00222 #ifdef DEBUG
00223     printf("nsAppShell: MyMainLoop exiting!\n");
00224 #endif
00225 }
00226 
00227 //-------------------------------------------------------------------------
00228 //
00229 // Run
00230 //
00231 //-------------------------------------------------------------------------
00232 NS_IMETHODIMP nsAppShell::Run()
00233 {
00234   if (!mEventQueue)
00235     Spinup();
00236 
00237   if (!mEventQueue)
00238     return NS_ERROR_NOT_INITIALIZED;
00239 
00240   // kick up gtk_main.  this won't return until gtk_main_quit is called
00241   MyMainLoop();
00242 
00243   Spindown();
00244 
00245   return NS_OK; 
00246 }
00247 
00248 //-------------------------------------------------------------------------
00249 //
00250 // Exit a message handler loop
00251 //
00252 //-------------------------------------------------------------------------
00253 
00254 NS_METHOD nsAppShell::Exit()
00255 {
00256   gExitMainLoop = PR_TRUE;
00257   return NS_OK;
00258 }
00259 
00260 
00261 #define NUMBER_HASH_KEY(_num) ((PLHashNumber) _num)
00262 
00263 static PLHashNumber
00264 IntHashKey(PRInt32 key)
00265 {
00266   return NUMBER_HASH_KEY(key);
00267 }
00268 
00269 NS_IMETHODIMP nsAppShell::ListenToEventQueue(nsIEventQueue *aQueue,
00270                                              PRBool aListen)
00271 {
00272 
00273   if (!sQueueHashTable) {
00274     sQueueHashTable = PL_NewHashTable(3, (PLHashFunction)IntHashKey,
00275                                       PL_CompareValues, PL_CompareValues, 0, 0);
00276   }
00277   if (!sCountHashTable) {
00278     sCountHashTable = PL_NewHashTable(3, (PLHashFunction)IntHashKey,
00279                                       PL_CompareValues, PL_CompareValues, 0, 0);
00280   }
00281 
00282   if (aListen) {
00283     /* add listener */
00284     PRInt32 key = aQueue->GetEventQueueSelectFD();
00285 
00286     /* only add if we arn't already in the table */
00287     if (!PL_HashTableLookup(sQueueHashTable, (void *)(key))) {
00288                      PRInt32 tag = PtAppAddFd( NULL, aQueue->GetEventQueueSelectFD(), (Pt_FD_READ | Pt_FD_NOPOLL | Pt_FD_DRAIN ),
00289                                                  event_processor_callback, aQueue );
00290 
00291       if (tag >= 0) {
00292         PL_HashTableAdd(sQueueHashTable, (void *)(key), (void *)(key));
00293       }
00294     }
00295     /* bump up the count */
00296     int count = (int)(PL_HashTableLookup(sCountHashTable, (void *)(key)));
00297     PL_HashTableAdd(sCountHashTable, (void *)(key), (void *)(count+1));
00298   } else {
00299     /* remove listener */
00300     PRInt32 key = aQueue->GetEventQueueSelectFD();
00301 
00302     int count = (int)(PL_HashTableLookup(sCountHashTable, (void *)(key)));
00303     if (count - 1 == 0) {
00304       int tag = (int)(PL_HashTableLookup(sQueueHashTable, (void *)(key)));
00305       if (tag > 0) {
00306        PtAppRemoveFd(NULL, key);
00307         PL_HashTableRemove(sQueueHashTable, (void *)(key));
00308       }
00309     }
00310     PL_HashTableAdd(sCountHashTable, (void *)(key), (void *)(count-1));
00311 
00312   }
00313 
00314   return NS_OK;
00315 }